Подтвердить что ты не робот

Почему Funcs не принимает более 16 аргументов?

Поскольку Javascript - это язык, на котором я наиболее опытный, я знаком с использованием функций как объектов первого класса. Я думал, что С# не хватало этой функции, но потом я услышал о Func и Action и delegate, которые, я думаю, довольно awesomesauce.

Например, вы можете объявить Func, который объединяет две строки и помещает пробел между ними следующим образом:

Func<string, string, string> concat = (a,b) => a + " " + b;

Я заметил, что когда вы печатаете

Func<

IntelliSense показывает, что он имеет 17 перегрузок:

delegate System.Func<out TResult>
delegate System.Func<in T, out TResult>
delegate System.Func<in T1, in T2, out TResult>
...snip...
delegate System.Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16, out TResult>

Это заставило меня рассмеяться. Я просмотрел документы MSDN для Func и снова засмеялся. Это заставило меня попытаться объявить Func с 17 аргументами. Это вызывает ошибку (Using the generic type 'System.Func<TResult>' requires 1 type arguments).

Я могу согласиться с тем, что, вероятно, не рекомендуется иметь Func, который принимает более 16 аргументов. Тем не менее, это похоже на kludgy путь для Func для реализации. Для документирования требуется 17 тривиально разных перегрузок. Это все, что ему действительно нужно знать: последний тип параметра - это тип возвращаемого значения, и все параметры типа перед ним являются типами аргументов.

Итак, что я мог сделать, если бы хотел создать Func с более чем 16 параметрами? Почему в любом случае существует предел? Почему С# не позволяет вам объявить Func с произвольным числом аргументов?

4b9b3361

Ответ 1

Вы надеетесь на что-то вроде аргументы вариационного типа, которых нет в С#. С# требует, чтобы арность родовых типов была исправлена, поэтому отвратительное распространение типов Func, Action и Tuple.

Если вы используете язык, эта функция была добавлена ​​в С++ 11, но вы, вероятно, должны просто использовать jQuery.: -)

Ответ 2

Вы можете просто определить любого делегата, который вам нужен. Таким образом, Func с 20 параметрами будет определен следующим образом:

public delegate R Func<
    P0, P1, P2, P3, P4, P5, P6, P7, P8, P9,
    P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, R>(
        P0 p0, P1 p1, P2 p2, P3 p3, P4 p4,
        P5 p5, P6 p6, P7 p7, P8 p8, P9 p9,
        P10 p10, P11 p11, P12 p12, P13 p13, P14 p14,
        P15 p15, P16 p16, P17 p17, P18 p18, P19 p19);

Затем вы можете использовать его следующим образом:

Func<
        int, int, int, int, int, int, int, int, int, int,
        int, int, int, int, int, int, int, int, int, int, int> f = (
            p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10,
            p11, p12, p13, p14, p15, p16, p17, p18, p19) =>
                p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9 + p10
                    + p11 + p12 + p13 + p14 + p15 + p16 + p17 + p18 + p19;

var r = f(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1);

С# также позволяет использовать лямбда-синтаксис для любого делегата, поэтому вы также можете сделать это:

public delegate R ArrayFunc<P, R>(params P[] parameters);

И затем используйте его так:

ArrayFunc<int, int> af = ps => ps.Sum();

var ar = af(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1);

Это очень гибкая и мощная функция языка.

Ответ 3

Я думаю, что понимаю, что вы можете делать с JavaScript и функциями (аргументами), преатитесь аккуратно, но он также не статически вводится.

Но обратите внимание, что вам никогда не нужно больше одного аргумента в функциональном программировании. Вы можете связать столько аргументов, сколько хотите, возвращая еще одну функцию (это общая черта в FP и сильно используется с использованием метода, доступного в JS, но только с изгибом системы).

Конечно, это похоже на С#:

Func<A1,Func<A2,Func<A3,...<Func<An,Result>>...> 
  x1 =>
    (x2 => 
      (x3 => 
        ... 
          (xn => 
              { /*return soomething */ }
  ))...);

но это то, что F # для;) и, конечно же, вы никогда не должны делать функцию с более чем несколькими аргументами (путь ниже 16!) во всяком случае.

Ответ 4

Вы можете создать свой собственный делегат с более чем 16 аргументами. Или вы можете использовать Tuple<T1, T2, T3, T4, T5, T6, T7, TRest> (или любую другую структуру данных) в качестве параметра.

Ответ 5

Делегаты System.Func, вероятно, существуют благодаря команде BCL.. кто понял, включая конечное число предопределенных общих делегатов, было бы удобно (и даже потребовалось бы для многих ситуаций).

Чтобы сделать то, что вы говорите, то есть неограниченное количество общих параметров для делегата Func потребует изменения языка. Ответственность будет лежать как с командами С#, так и с vb.net(и, возможно, с другими), чтобы изменить язык на разрешите это.

Возможно, в какой-то момент, если преимущество этой функции перевешивает стоимость предопределения нескольких делегатов Func, и это более важно, чем другие изменения языка (и что это не прерывное изменение) улокальных команд моего внедрения неограниченные общие параметры.. может быть не на какое-то время, хотя!

Ответ 6

Why is there a limit anyway?

Существует мнение, что функция, вероятно, не должна содержать более трех аргументов. Если этого больше, становится все труднее понять. Конечно, это не может быть причиной того, что именно так в С#, но это ограничение, возможно, не так уж плохо.

Я бы сказал, что даже этот предел 16 слишком много, и он уже ободряет плохой дизайн.