naw*_*fal 30
我觉得这里其他的答案谈论的是什么Action
/ Func
是和它的使用.我将尝试回答如何在Action
/ Func
和方法之间进行选择.差异首先:
1)从原始性能的角度来看,与直接方法调用相比,代表的速度较慢,但是如此令人担忧,以至于担心它是一种不好的做法.
2)方法可以有重载(具有不同签名的相同函数名)但不具有Action
/ Func
委托,因为它们被声明为变量,并且通过C#规则,您不能在给定范围内具有两个具有相同名称的变量.
bool IsIt() { return 1 > 2; }
bool IsIt(int i) { return i > 2; } //legal
Func<bool> IsIt = () => 1 > 2;
Func<int, bool> IsIt = i => i > 2; //illegal, duplicate variable naming
Run Code Online (Sandbox Code Playgroud)
3)因此,Action
/ Func
是可重新分配的并且可以指向任何函数,而编译后的方法永远保持相同.Func/Action
如果它指向的方法在运行时期间永远不会改变,那么它在语义上是错误的.
bool IsIt() { return 1 > 2; } //always returns false
Func<bool> IsIt = () => 1 > 2;
IsIt = () => 2 > 1; //output of IsIt depends on the function it points to.
Run Code Online (Sandbox Code Playgroud)
4)您可以为常规方法指定ref
/ out
参数.例如,你可以拥有
bool IsIt(out string p1, ref int p2) { return 1 > 2; } //legal
Func<out string, ref int, bool> IsIt; //illegal
Run Code Online (Sandbox Code Playgroud)
5)您不能为Action
/ 引入新的泛型类型参数Func
(它们是通用的btw,但类型参数只能是父方法或类中指定的已知类型),与方法不同.
bool IsIt<A, R>() { return 1 > 2; } //legal
Func<bool> IsIt<A, R> = () => 1 > 2; //illegal
Run Code Online (Sandbox Code Playgroud)
6)方法可以有可选参数,而不是Action
/ Func
.
bool IsIt(string p1 = "xyz") { return 1 > 2; } //legal
Func<string, bool> IsIt = (p1 = "xyz") => 1 > 2; //illegal
Run Code Online (Sandbox Code Playgroud)
7)您可以params
为方法的参数设置关键字,而不是Action
/ Func
.
bool IsIt(params string[] p1) { return 1 > 2; } //legal
Func<params string[], bool> IsIt = p1 => 1 > 2; //illegal
Run Code Online (Sandbox Code Playgroud)
8) Intellisense可以很好地使用方法的参数名称(因此你有很酷的XML文档可用于方法),而不是Action
/ Func
.因此,就可读性而言,常规方法获胜.
9) Action
/Func
参数限制为16(不是你不能用更多的方法定义你自己的参数),但方法支持的比你需要的多.
至于何时使用哪个,我会考虑以下几点:
当你被迫使用基于上述任何一点的那个,那么你无论如何也别无选择.第3点是我发现最引人注目的,你必须根据这个决定作出决定.
在大多数正常情况下,常规方法是可行的方法.这是在C#和VB.NET世界中重构一组通用功能的标准方法.
根据经验,如果函数不仅仅是一行,我更喜欢一种方法.
如果函数在特定方法之外没有相关性,并且函数太简单了,比如简单的selector(Func<S, T>
)或谓词(Func<bool>
)我更喜欢Action
/ Func
.例如,
public static string GetTimeStamp()
{
Func<DateTime, string> f = dt => humanReadable
? dt.ToShortTimeString()
: dt.ToLongTimeString();
return f(DateTime.Now);
}
Run Code Online (Sandbox Code Playgroud)可能存在Action
/ Func
更有意义的情况.例如,如果你必须构建一个繁重的表达式并编译一个委托,那么它只需要执行一次并缓存已编译的委托.
public static class Cache<T>
{
public static readonly Func<T> Get = GetImpl();
static Func<T> GetImpl()
{
//some expensive operation here, and return a compiled delegate
}
}
Run Code Online (Sandbox Code Playgroud)
代替
public static class Cache<T>
{
public static T Get()
{
//build expression, compile delegate and invoke the delegate
}
}
Run Code Online (Sandbox Code Playgroud)
在第一种情况下,当你调用时Get
,GetImpl
只执行一次,而在第二种情况下,Get
每次都会调用(昂贵的).
不要忘记匿名方法本身会有一些无关的限制Func/Action
,使得使用方式略有不同.另请参阅此相关问题.
Chr*_*ain 23
Action和Func是框架提供的委托类型.委托允许将函数视为变量,这意味着您可以(除其他外)将它们从方法传递给方法.如果您曾使用C++编程,则可以将Delegates视为受其引用的方法的签名限制的函数指针.
Action和Func特别是通用委托(意思是它们采用类型参数)和一些最常见的签名 - 几乎所有程序中的任何方法都可以使用这两个中的一个或另一个来表示,从而节省了人们大量时间手动定义委托我们在版本2之前的.net中做过.事实上,当我在项目中看到这样的代码时,我通常可以安全地假设项目是从.net 1.1迁移的:
// This defines a delegate (a type that represents a function)
// but usages could easily be replaced with System.Action<String>
delegate void SomeApplicationSpecificName(String someArgument);
Run Code Online (Sandbox Code Playgroud)
我建议您再考虑一下代表们.它们是C#语言的一个非常强大的功能.
我用它们来创建一个函数数组。例如,我可能有一个包含可以执行的操作的 ComboBox。我用类或结构的项目填充 ComboBox:
public class ComboBoxAction
{
private string text;
private Action method;
public ComboBoxAction(string text, Action method)
{
this.text = text;
this.method = method;
}
public override string ToString()
{
return this.text;
}
public void Go()
{
this.method();
}
}
Run Code Online (Sandbox Code Playgroud)
然后当有人选择一个项目时,我可以调用该操作。
CType(ComboBox1.SelectedItem, ComboBoxAction).Go()
Run Code Online (Sandbox Code Playgroud)
这比让 Select 语句根据 ComboBox 的文本确定要调用的方法要容易得多。
归档时间: |
|
查看次数: |
14874 次 |
最近记录: |