Func<> 委托有啥了不起的?
Posted
技术标签:
【中文标题】Func<> 委托有啥了不起的?【英文标题】:What's so great about Func<> delegate?Func<> 委托有什么了不起的? 【发布时间】:2010-09-24 02:28:52 【问题描述】:对不起,如果这是基本的,但我正在尝试使用 .Net 3.5。
问题:Func 有 5 个重载吗?从外观上看,我仍然可以自己创建一个类似的委托,例如 MyFunc,它具有确切的 5 个重载,甚至更多。
例如:public delegate TResult MyFunc<TResult>()
和各种重载的组合...
这个想法是在我试图理解 Func 委托时出现的,并遇到了以下场景:
Func<int,int> myDelegate = (y) => IsComposite(10);
这意味着委托具有一个 int 类型的参数和一个 int 类型的返回类型。有五种变体(如果您通过智能感知查看重载)。所以我猜我们可以有一个没有返回类型的委托?
那么我是否有理由说 Func 没什么了不起,只是 .Net 框架中的一个示例,我们可以使用它,如果需要,创建自定义“func”委托以满足我们自己的需要?
谢谢,
【问题讨论】:
【参考方案1】:伟大之处在于建立共享语言以更好地沟通。
不要为同一事物定义自己的委托类型(委托爆炸),而是使用框架提供的委托类型。任何阅读您的代码的人都会立即掌握您要完成的工作。. 最大限度地减少“这段代码实际上在做什么?”的时间。 所以当我看到一个
Action = 一些只做某事但不返回输出的方法 Comparison = 比较两个相同类型的对象并返回一个 int 来指示顺序的方法 转换器 = 将 Obj A 转换为等效的 Obj B EventHandler = 给定事件参数形式的某些输入,对某个对象引发的事件的响应/处理程序 Func = 一些接受一些参数、计算并返回结果的方法 谓词 = 根据某些标准评估输入对象并将通过/失败状态返回为 bool除非它是我直接关注的领域,否则我不必深入挖掘。因此,如果您觉得您需要的代表符合其中一项需求,请在推出自己的委托之前使用它们。
免责声明:我个人喜欢语言设计者的这一举动。
反论点:有时定义代理可能有助于更好地传达意图。例如System.Threading.ThreadStart
超过 System.Action
。所以说到底是个判断。
【讨论】:
不,你的答案更好。我很高兴 Func/Action 在那里,它们通常就足够了——但我认为仍然有一些时候值得定义你自己的代表。一个很好的例子是谓词 - 当已经存在 FuncAction
或Func
。【参考方案2】:
Func
委托家族(以及它们的无返回类型表亲,Action
)并不比您在 .NET 框架中找到的任何其他东西都要大。它们只是为了重复使用,因此您不必重新定义它们。它们具有类型参数以保持通用性。例如, Func
您应该能够将内置的 Func
委托用于任何接受最多 4 个参数的返回值方法,而不是为此目的定义您自己的委托,除非您希望名称反映您的意图,这很酷。
您绝对需要定义委托类型的情况包括接受超过 4 个参数的方法、带有 out、ref 或 params 的方法em> 参数或递归方法签名(例如,delegate Foo Foo(Foo f)
)。
【讨论】:
【参考方案3】:除了马克思的正确答案:
值得注意的是 Func 的相关家族,Action
代表。同样,这些类型重载了类型参数的数量,但声明为返回 void。
如果您想在 .NET 2.0 项目中使用 Func/Action,但以后通过简单的方式升级,您可以从我的version comparison page 中剪切和粘贴声明。如果您在 System
命名空间中声明它们,那么您只需稍后删除声明即可升级 - 但是您将无法(轻松)在 .NET 3.5 中构建相同的代码没有 删除声明。
【讨论】:
【参考方案4】:解耦依赖和邪恶的捆绑是一件让它变得很棒的独特的事情。其他所有可以辩论并声称以某种本土方式可行的东西。
我一直在用一个旧的和沉重的库重构稍微复杂的系统,但由于无法打破编译时间依赖性而被阻止 - 因为潜伏在“另一边”的命名委托。所有程序集加载和反射都没有帮助 - 编译器会拒绝将委托() ... 转换为对象,并且无论您做什么来安抚它都会失败。
在编译时结构性的委托类型比较在此之后变成名义上的(加载、调用)。当您考虑“我亲爱的库将被所有人永远使用”时,这似乎没问题,但它不能扩展到更复杂的系统。 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);
现有代码没有注意到差异,新代码没有得到依赖 - 地球上的和平:-)
【讨论】:
【参考方案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
【讨论】:
以上是关于Func<> 委托有啥了不起的?的主要内容,如果未能解决你的问题,请参考以下文章