Почему Funcs не принимает более 16 аргументов? - PullRequest
21 голосов
/ 27 сентября 2011

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

Например, вы можете объявить 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 аргументов. Тем не менее, это выглядит как грязный способ реализации Func. Для документирования требуется 17 тривиально разных перегрузок. Это все, что нужно знать: последний параметр типа - это тип возвращаемого значения, а все параметры типа перед ним - это типы аргументов.

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

Ответы [ 6 ]

18 голосов
/ 27 сентября 2011

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

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

15 голосов
/ 27 сентября 2011

Вы можете просто определить любой делегат, который вам нужен.Таким образом, 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);

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

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);

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

7 голосов
/ 27 сентября 2011

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

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

Конечноэто плохо для C #:

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

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

1 голос
/ 27 сентября 2011

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

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

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

1 голос
/ 27 сентября 2011

Why is there a limit anyway?

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

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

1 голос
/ 27 сентября 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...