Что такого хорошего в Func <> делегате?
Извините, если это базовое, но я пытался забрать .Net 3.5.
Вопрос: Есть ли что-нибудь замечательное в перегрузках Func < > и it 5? По внешнему виду я все же могу создать подобный дедгейт по своему собственному слову MyFunc < > с точными 5 перегрузками и даже более.
например: public delegate TResult MyFunc<TResult>()
и комбо различных перегрузок...
Мысль возникла, когда я пытался понять делегатов Func < > и использовал следующий сценарий:
Func<int,int> myDelegate = (y) => IsComposite(10);
Это подразумевает делегат с одним параметром типа int и возвращаемым типом типа int. Существует пять вариантов (если вы посмотрите на перегрузки через intellisense). Поэтому я предполагаю, что у нас может быть делегат без возвращаемого типа?
Итак, я оправдан в том, что Func < > не является чем-то большим и просто примером в .Net-среде, которую мы можем использовать и при необходимости, создавать пользовательские делегаты "func < > " в соответствии с нашими собственными потребностями?
Спасибо,
Ответы
Ответ 1
Величие заключается в установлении общего языка для лучшей коммуникации.
Вместо того, чтобы определять собственные типы делегатов для одной и той же вещи (взлом делегата), используйте те, которые предоставляются инфраструктурой. Любой, кто читает ваш код, мгновенно захватывает то, что вы пытаетесь выполнить. Сводит к минимуму время на "то, что на самом деле делает этот кусок кода"?
Поэтому, как только я увижу
- Действие= некоторый метод, который просто что-то делает и не возвращает выход
- Сравнение= некоторый метод, который сравнивает два объекта одного типа и возвращает int для указания порядка
- Конвертер= преобразует Obj A в эквивалент Obj B
- EventHandler= ответ/обработчик события, вызванного каким-либо объектом, с учетом некоторого ввода в форме аргумента события
- Func= некоторый метод, который принимает некоторые параметры, вычисляет что-то и возвращает результат
- Predicate= оценивать входной объект по некоторым критериям и возвращать статус pass/fail как bool
Мне не нужно копать глубже, чем это, если это не моя непосредственная область беспокойства. Поэтому, если вы чувствуете, что делегат, который вам нужен, подходит для одной из этих потребностей, используйте их, прежде чем сворачивать свои собственные.
Отказ от ответственности: Лично мне нравится этот шаг разработчиков языка.
Контр-аргумент. Иногда определение вашего делегата может помочь улучшить связь. например System.Threading.ThreadStart
над System.Action
. Итак, в конце концов, это решение.
Ответ 2
Семейство делегатов Func
(и их двоюродных братьев с возвратным типом, Action
) не больше, чем что-либо еще, что вы найдете в платформе .NET. Они просто для повторного использования, поэтому вам не нужно их переопределять. У них есть параметры типа, чтобы сохранить общий характер. Например, Func < T0, bool > совпадает с делегатом System.Predicate <T> . Они были первоначально разработаны для LINQ.
Вы должны просто использовать встроенный делегат Func
для любого метода возвращающего значение, который принимает до 4 аргументов вместо определения собственного делегата для такой цели, если вы не хотите, чтобы имя отражало ваше намерение, который является прохладным.
Случаи, в которых вам абсолютно необходимо определить ваши типы делегатов, включают методы, которые принимают более 4 аргументов, методы с параметрами out, ref или params или сигнатуры рекурсивных методов (например, delegate Foo Foo(Foo f)
).
Ответ 3
В дополнение к Марксидаду правильный ответ:
- Стоит знать о родстве Func, делегатах
Action
. Опять же, это типы, перегруженные количеством параметров типа, но объявленные для возврата void.
- Если вы хотите использовать Func/Action в проекте .NET 2.0, но с простым путем для обновления позже, вы можете вырезать и вставлять объявления из страница сравнения версий. Если вы объявите их в пространстве имен
System
, вы сможете обновить, просто удалив объявления позже, но тогда вы не сможете (легко) создать тот же код в .NET 3.5 без удаления объявлений.
Ответ 4
Развязывание зависимостей и нечестивые привязки - одна из особенностей, которая делает ее замечательной. Все остальное можно обсуждать и утверждать, что оно выполнимо в некотором роде.
Я занимался реорганизацией немного более сложной системы со старой и тяжелой библиотекой и был заблокирован из-за невозможности нарушить зависимость времени компиляции - из-за того, что именованный делегат скрывается на "другой стороне". Вся загрузка и отражение сборки не помогли - компилятор отказался просто отдать делегат() {...} объекту, и все, что вы делаете для его умиротворения, потерпит неудачу с другой стороны.
Сравнение типов делегатов, которое является структурным во время компиляции, становится номинальным после этого (загрузка, вызов). Это может показаться правильным, пока вы думаете, что "моя любимая библиотека будет использоваться навсегда и для всех", но она не масштабируется даже в несколько более сложных системах. Шаблоны развлечений < > привносят степень структурной эквивалентности в мир номинальной типизации. Это тот аспект, которого вы не можете достичь, выставив свой собственный.
Пример - преобразование:
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);
Существующий код не замечает разницы, новый код не получает зависимости - мир на Земле: -)
Ответ 5
Одна вещь, которую мне нравится в делегатах, - это то, что они позволяют мне объявлять методы в таких методах, это удобно, когда вы хотите повторно использовать кусок кода, но вам нужно только в этом методе. Так как цель здесь - ограничить область действия, насколько это возможно, 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"));
Ответ 6
Хотя это старый поток, мне пришлось добавить, что func < > и action < > также помогают нам использовать ковариацию и противоположную дисперсию.
http://msdn.microsoft.com/en-us/library/dd465122.aspx