Что хорошего в делегате Func <>? - PullRequest
25 голосов
/ 26 ноября 2008

Извините, если это основной, но я пытался поднять на .Net 3.5.

Вопрос: Есть ли что-то замечательное в Func <>, и это 5 перегрузок? Судя по всему, я все еще могу создать аналогичный delgate, скажем так, MyFunc <> с точными 5 перегрузками и даже больше.

например: public delegate TResult MyFunc<TResult>() и комбинация различных перегрузок ...

Мысль возникла, когда я пытался понять делегатов Func <>, и наткнулся на следующий сценарий:

Func<int,int> myDelegate = (y) => IsComposite(10);

Это подразумевает делегата с одним параметром типа int и типом возвращаемого значения типа int. Существует пять вариантов (если вы посмотрите на перегрузки через intellisense). Итак, я предполагаю, что у нас может быть делегат без возвращаемого типа?

Итак, могу ли я сказать, что Func <> - это не что иное, как просто пример в среде .Net, который мы можем использовать и, если необходимо, создавать собственные делегаты "func <>" для удовлетворения наших собственных потребностей?

Спасибо

Ответы [ 6 ]

64 голосов
/ 26 ноября 2008

Величие заключается в создании общего языка для лучшего общения .

Вместо того, чтобы определять собственные типы делегатов для одной и той же вещи (взрыв делегата), используйте типы, предоставляемые каркасом. Любой, кто читает ваш код, мгновенно понимает, чего вы пытаетесь достичь ... сводит к минимуму время на то, «что на самом деле делает этот фрагмент кода»? Так что, как только я увижу

  • Действие = некоторый метод, который просто что-то делает и не возвращает ничего
  • Сравнение = некоторый метод, который сравнивает два объекта одного типа и возвращает int для указания порядка
  • Конвертер = преобразовывает Obj A в эквивалентный Obj B
  • EventHandler = ответ / обработчик на событие, вызванное каким-либо объектом, с некоторым вводом в виде аргумента события
  • Func = некоторый метод, который принимает некоторые параметры, что-то вычисляет и возвращает результат
  • Predicate = оценивать входной объект по некоторым критериям и возвращать состояние прохождения / сбоя как bool

Мне не нужно копать глубже этого, если это не является моей непосредственной проблемой. Поэтому, если вы чувствуете, что делегат, который вам нужен, соответствует одному из этих требований, используйте его, прежде чем переходить на свой собственный.

Отказ от ответственности: Лично мне нравится этот шаг дизайнеров языка.

Встречный аргумент : Иногда определение вашего делегата может помочь лучше понять намерения. например System.Threading.ThreadStart более System.Action. В конце концов, это призыв к суду.

12 голосов
/ 26 ноября 2008

Семейство Func делегатов (и их двоюродные братья без возвращаемого типа, Action) ничем не превосходят то, что вы можете найти в .NET Framework. Они просто для повторного использования, поэтому вам не нужно переопределять их. У них есть параметры типа, чтобы сделать вещи общими. Например, Func совпадает с делегатом System.Predicate . Первоначально они были разработаны для LINQ.

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

Случаи, когда вам абсолютно необходимо определить типы делегатов, включают методы, которые принимают более 4 аргументов, методы с параметрами out , ref или params или сигнатуры рекурсивного метода (например, delegate Foo Foo(Foo f)).

9 голосов
/ 26 ноября 2008

В дополнение к правильному ответу Марксидада:

  • Стоит знать о родственниках Func, делегатах Action. Опять же, это типы, перегруженные числом параметров типа, но объявленные как возвращающие void.
  • Если вы хотите использовать Func / Action в проекте .NET 2.0, но с простым путем к обновлению позже, вы можете вырезать и вставить объявления со страницы сравнения версий . Если вы объявите их в пространстве имен System, вы сможете выполнить обновление, просто удалив объявления позже - но тогда вы не сможете (легко) создать тот же код в .NET 3.5 без удаление объявлений.
7 голосов
/ 25 июня 2010

Разделение зависимостей и нечестивых связей - это одна особенность, которая делает его великолепным. Все остальное можно обсуждать и утверждать, что оно выполнимо каким-то домашним способом.

Я проводил рефакторинг немного более сложной системы со старой и тяжелой библиотекой и был заблокирован из-за невозможности разорвать зависимость от времени компиляции - из-за именованного делегата, скрывающегося на «другой стороне». Вся загрузка сборки и отражение не помогли - компилятор отказался бы просто приводить делегат () {...} к объекту, и что бы вы ни делали для его усмирения, оно не сработало бы с другой стороны.

Сравнение типов делегатов, которое является структурным во время компиляции, становится номинальным после этого (загрузка, вызов). Это может показаться нормальным, если вы думаете, что «моя дорогая библиотека будет использоваться навсегда и всеми», но она не масштабируется даже до более сложных систем. Шаблоны Fun <> возвращают степень структурной эквивалентности обратно в мир номинальной типизации. Это тот аспект, которого вы не можете достичь, разворачивая свой собственный.

Пример - преобразование:

class Session ( 
    public delegate string CleanBody();    // tying you up and you don't see it :-)
    public static void Execute(string name, string q, CleanBody body) ... 

до:

    public static void Execute(string name, string q, Func<string> body)

Позволяет полностью независимому коду выполнять вызов отражения, например:

Type type = Type.GetType("Bla.Session, FooSessionDll", true); 
MethodInfo methodInfo = type.GetMethod("Execute"); 

Func<string> d = delegate() { .....}  // see Ma - no tie-ups :-)
Object [] params = { "foo", "bar", d};
methodInfo.Invoke("Trial Execution :-)", params);

Существующий код не замечает разницы, новый код не получает зависимости - мир на Земле: -)

1 голос
/ 02 января 2012

Одна вещь, которая мне нравится в делегатах, это то, что они позволяют мне объявлять методы внутри методов следующим образом: это удобно, когда вы хотите повторно использовать кусок кода, но он нужен только в этом методе. Поскольку цель здесь состоит в том, чтобы максимально ограничить область видимости, Func <> пригодится.

Например:

string FormatName(string pFirstName, string pLastName) {
    Func<string, string> MakeFirstUpper = (pText) => {
        return pText.Substring(0,1).ToUpper() + pText.Substring(1);
    };

    return MakeFirstUpper(pFirstName) + " " + MakeFirstUpper(pLastName);
}

Это даже проще и удобнее, когда вы можете использовать логический вывод, который вы можете сделать, если создадите вспомогательную функцию, например, так:

Func<T, TReturn> Lambda<T, TReturn>(Func<T, TReturn> pFunc) {
    return pFunc;
}

Теперь я могу переписать свою функцию без Func <>:

string FormatName(string pFirstName, string pLastName) {
    var MakeFirstUpper = Lambda((string pText) => {
        return pText.Substring(0,1).ToUpper() + pText.Substring(1);
    });

    return MakeFirstUpper(pFirstName) + " " + MakeFirstUpper(pLastName);
}

Вот код для проверки метода:

Console.WriteLine(FormatName("luis", "perez"));
0 голосов
/ 05 декабря 2010

Хотя это старая ветка, мне пришлось добавить, что func <> и action <> также помогают нам использовать ковариацию и противоположную дисперсию.

http://msdn.microsoft.com/en-us/library/dd465122.aspx

...