很抱歉,如果这是基本的,但我试图接受.Net 3.5。
问题:Func<>有什么好处吗?这是5次超载?从它的外观来看,我仍然可以自己创建一个类似的delgate,MyFunc<>精确的5次重载甚至更多。
例如:public delegate TResult MyFunc<TResult>()
和各种重载的组合......
当我试图理解Func&lt;&gt;时,想到了这个想法。代表们,并点击以下场景:
Func<int,int> myDelegate = (y) => IsComposite(10);
这意味着一个委托有一个int类型的参数和一个int类型的返回类型。有五种变体(如果你通过intellisense查看重载)。所以我猜我们可以有一个没有返回类型的委托?
所以我有理由说Func&lt;&gt;并不是什么好事,只是我们可以使用的.Net框架中的一个例子,如果需要,创建自定义“func&lt;&gt;”代表们是否符合我们自己的需求?
谢谢,
答案 0 :(得分:64)
伟大之处在于建立共享语言以促进沟通。
不是为同一事物(委托爆炸)定义自己的委托类型,而是使用框架提供的委托类型。任何阅读你的代码的人都会立即掌握你想要完成的任务。最大限度地减少“这段代码实际上做了什么?”的时间。 所以,一看到
除非是我直接关注的领域,否则我不必深入挖掘。因此,如果您觉得您需要的代表满足其中一个需求,请在使用它们之前使用它们。
免责声明:我个人喜欢语言设计师的这一举动。
反驳:有时定义您的委托可能有助于更好地传达意图。例如System.Threading.ThreadStart
超过System.Action
。所以这最终是一次判断。
答案 1 :(得分:12)
Func
代表系列(及其返回类型的堂兄弟,Action
)并不比在.NET框架中找到的任何其他内容更重要。它们只是在那里重复使用,所以你不必重新定义它们。它们具有类型参数以保持通用性。例如,Func&lt; T0,bool&gt;与System.Predicate&lt; T&gt;相同代表。它们最初是为LINQ设计的。
你应该能够只使用内置的Func
委托来接受最多4个参数的值返回方法,而不是为了这个目的而定义你自己的委托,除非你希望这个名字反映你的名字意图,这很酷。
您绝对需要定义委托类型的情况包括接受4个以上参数的方法, out , ref 或 params的方法参数或递归方法签名(例如,delegate Foo Foo(Foo f)
)。
答案 2 :(得分:9)
除了马克思主义者的正确答案:
Action
代表。同样,这些是由类型参数的数量重载的类型,但声明为返回void。System
命名空间中声明它们,那么你将能够通过稍后删除声明来升级 - 但是你将无法(轻松地)在.NET 3.5中构建相同的代码没有删除声明。答案 3 :(得分:7)
解耦依赖关系和邪恶的合作是一个非常好的事情。其他所有人都可以辩论并声称可以用自己种植的方式行事。
我一直在使用旧的和重型的lib重构稍微复杂的系统,并因无法破坏编译时依赖性而被阻止 - 因为命名的委托潜伏在“另一边”。所有程序集加载和反射都没有帮助 - 编译器会拒绝将委托(){...}强制转换为对象,无论你做什么来安抚它都会失败。
在编译时结构化的委托类型比较在此之后变为名义(加载,调用)。当你想到“我亲爱的lib将永远被所有人使用”时,这看起来似乎没问题,但它不能扩展到更复杂的系统。娱乐和LT;&GT;模板将一定程度的结构等同性带回到名义类型的世界中。这是你推出自己无法实现的方面。
示例 - 转换:
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);
现有代码没有注意到差异,新代码没有依赖 - 地球上的和平: - )
答案 4 :(得分:1)
我喜欢委托的一件事是他们允许我在类似方法中声明方法,当你想重用一段代码而你只需要在那个方法中使用它时,这很方便。由于此处的目的是尽可能地限制范围Func&lt;&gt;派上用场。
例如:
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&lt;&gt;:
的情况下重写我的函数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"));
答案 5 :(得分:-1)
虽然这是一个旧线程我不得不添加func&lt;&gt;和行动&lt;&gt;也帮助我们使用协方差和逆变量。