Eli*_*eth 67 c# delegates action func
今天我在考虑宣布这个:
private delegate double ChangeListAction(string param1, int number);
Run Code Online (Sandbox Code Playgroud)
但为什么不用这个:
private Func<string, int, double> ChangeListAction;
Run Code Online (Sandbox Code Playgroud)
或者如果ChangeListAction
没有返回值,我可以使用:
private Action<string,int> ChangeListAction;
Run Code Online (Sandbox Code Playgroud)
那么使用delegate
关键字声明委托的优势在哪里?
是因为.NET 1.1,随着.NET 2.0的出现Action<T>
和.NET 3.5的出现Func<T>
?
naw*_*fal 71
的出现Action
和Func
代表的家庭已使定制的代表较少使用,但后者仍可以找到用途.自定义代表的优点包括:
正如其他人指出,清楚表达的意图不像通用Action
和Func
(帕特里克大约有有意义的参数名称非常好的点).
与其他两个泛型委托不同,您可以指定ref
/ out
参数.例如,你可以拥有
public delegate double ChangeListAction(out string p1, ref int p2);
Run Code Online (Sandbox Code Playgroud)
但不是
Func<out string, ref int, double> ChangeListAction;
Run Code Online (Sandbox Code Playgroud)此外,对于自定义委托,您只需要ChangeListAction
在代码库中的某个位置编写(我的意思是定义),而如果您没有定义一个,则必须在Func<string, int, double>
所有地方乱丢.在后一种情况下改变签名将是一个麻烦 - 一个不干的坏情况.
可以有可选参数.
public delegate double ChangeListAction(string p1 = "haha", int p2);
Run Code Online (Sandbox Code Playgroud)
但不是
Func<string, int, double> ChangeListAction = (p1 = "haha", p2) => (double)p2;
Run Code Online (Sandbox Code Playgroud)您可以拥有params
方法参数的关键字,而不是Action/Func
.
public delegate double ChangeListAction(int p1, params string[] p2);
Run Code Online (Sandbox Code Playgroud)
但不是
Func<int, params string[], double> ChangeListAction;
Run Code Online (Sandbox Code Playgroud)好吧,如果你真的运气不好,需要参数超过16(目前):)
至于优点Action
和Func
:
它快速而又脏,我全身都用它.如果用例很简单,它会使代码变短(自定义委托与我一起过时).
更重要的是,它的类型跨域兼容.Action
并且Func
是框架定义的,只要参数类型匹配,它们就可以无缝地运行.你不能拥有ChangeSomeAction
的 ChangeListAction
.Linq
发现了这方面的很好用处.
Mar*_*ers 54
优点是清晰度.通过给类型一个明确的名称,读者可以更清楚地知道它的作用.
在编写代码时,它也会对您有所帮助.像这样的错误:
cannot convert from Func<string, int, double> to Func<string, int, int, double>
Run Code Online (Sandbox Code Playgroud)
没有比说:
cannot convert from CreateListAction to UpdateListAction
Run Code Online (Sandbox Code Playgroud)
这也意味着如果你有两个不同的委托,它们都采用相同类型的参数,但在概念上做两件完全不同的事情,编译器可以确保你不会意外地使用你所指的另一个.
Sti*_*gar 11
明确声明委托可以帮助进行某些类型检查.编译器可以确保分配给变量的委托旨在用作ChangeListAction,而不是一些恰好与签名兼容的随机操作.
然而,声明自己的委托的真正价值在于它赋予它语义含义.阅读代码的人将通过其名称知道代表正在做什么.想象一下,如果你有一个包含三个int字段的类,而是声明了一个包含三个int元素的数组.数组可以做同样的事情,但字段的名称带来了对开发人员有用的语义信息.
在设计像LINQ这样的通用库时,应该使用Func,Predicate和Action委托.在这种情况下,委托没有预定义的语义,除了它们将执行和操作或用作谓词的事实.
另外还有一个类似的权衡问题,即Tuple vs匿名类型vs声明你自己的类.你可以把所有东西都放在一个元组中,但是属性只是Item1,Item2,它没有说明该类型的使用.
正如一些答案所提到的那样,胜利是清晰的,你可以为类型命名,因此对于api的用户来说更容易理解.我会说 - 在大多数情况下 - 为你的公共api声明委托类型,但在Func<?,?>
内部使用它是完全正常的.
声明其他答案中未提及的委托类型的一个巨大好处是,除了给类型命名之外,您实际上也可以命名参数,这将大大增加可用性.
我找到了一个特殊的用例,你只能使用委托:
public delegate bool WndEnumProc(IntPtr hwnd, IntPtr lParam);
[DllImport("User32.dll")]
public static extern bool EnumWindows(WndEnumProc lpEnumFunc, IntPtr lParam);
Run Code Online (Sandbox Code Playgroud)
使用Func/Action不起作用'Namespace.Class.WndEnumProc' is a 'field' but is used like a 'type'
::
public Func<IntPtr, IntPtr, bool> WndEnumProc;
[DllImport("User32.dll")]
public static extern bool EnumWindows(WndEnumProc lpEnumFunc, IntPtr lParam);
Run Code Online (Sandbox Code Playgroud)
以下代码进行编译,但在运行时抛出异常,因为System.Runtime.InteropServices.DllImportAttribute
不支持封送泛型类型:
[DllImport("User32.dll")]
public static extern bool EnumWindows(Func<IntPtr, IntPtr, bool> lpEnumFunc, IntPtr lParam);
Run Code Online (Sandbox Code Playgroud)
我提出这个例子向每个人展示:有时委托是你唯一的选择.这是对你的问题的合理答案why not use Action<T>/Func<T> ?