尽管我将专注于第一点,但我首先在整个性能问题上给出我的 2 美分。除非差异很大或使用量很大,否则我通常不会担心添加后对用户没有任何可见差异的微秒。我强调,我只在考虑非密集调用方法时才在意。我确实有特殊性能考虑的地方是我设计应用程序本身的方式。我关心缓存,关心线程的使用,关心调用方法的巧妙方法(是进行多次调用还是尝试只进行一次调用),是否池化连接等等。实际上我通常不关心不关注原始性能,而是关注可扩展性。我不在乎它是否对单个用户运行得更好一点纳秒,
话虽如此,我对第 1 点的看法如下。我喜欢匿名方法。它们给了我很大的灵活性和优雅的代码。匿名方法的另一个重要特性是它们允许我直接使用容器方法中的局部变量(当然,从 C# 的角度来看,而不是从 IL 的角度来看)。他们经常为我节省大量代码。我什么时候使用匿名方法?每次我需要的代码在其他地方都不需要。如果在两个不同的地方使用它,我不喜欢复制粘贴作为重用技术,所以我将使用普通的 ol' 委托。所以,就像 shoosh 回答的那样,重复代码是不好的。理论上没有性能差异,因为匿名是 C# 技巧,而不是 IL 东西。
我对匿名方法的大部分想法都适用于 lambda 表达式,因为后者可以用作表示匿名方法的紧凑语法。让我们假设以下方法:
public static void DoSomethingMethod(string[] names, Func<string, bool> myExpression)
{
Console.WriteLine("Lambda used to represent an anonymous method");
foreach (var item in names)
{
if (myExpression(item))
Console.WriteLine("Found {0}", item);
}
}
它接收一个字符串数组,对于每个字符串,它将调用传递给它的方法。如果该方法返回 true,它将显示“Found...”。您可以通过以下方式调用此方法:
string[] names = {"Alice", "Bob", "Charles"};
DoSomethingMethod(names, delegate(string p) { return p == "Alice"; });
但是,您也可以通过以下方式调用它:
DoSomethingMethod(names, p => p == "Alice");
两者之间的 IL 没有区别,因为使用 Lambda 表达式的那个更具可读性。再一次,没有性能影响,因为这些都是 C# 编译器技巧(不是 JIT 编译器技巧)。正如我不觉得我们过度使用匿名方法一样,我也不觉得我们过度使用 Lambda 表达式来表示匿名方法。当然,同样的逻辑也适用于重复代码:不要使用 lambda,使用常规委托。还有其他限制会导致您回到匿名方法或普通委托,例如 out 或 ref 参数传递。
Lambda 表达式的另一个好处是完全相同的语法不需要表示匿名方法。Lambda 表达式还可以表示……您猜对了,表达式。举个例子:
public static void DoSomethingExpression(string[] names, System.Linq.Expressions.Expression<Func<string, bool>> myExpression)
{
Console.WriteLine("Lambda used to represent an expression");
BinaryExpression bExpr = myExpression.Body as BinaryExpression;
if (bExpr == null)
return;
Console.WriteLine("It is a binary expression");
Console.WriteLine("The node type is {0}", bExpr.NodeType.ToString());
Console.WriteLine("The left side is {0}", bExpr.Left.NodeType.ToString());
Console.WriteLine("The right side is {0}", bExpr.Right.NodeType.ToString());
if (bExpr.Right.NodeType == ExpressionType.Constant)
{
ConstantExpression right = (ConstantExpression)bExpr.Right;
Console.WriteLine("The value of the right side is {0}", right.Value.ToString());
}
}
注意稍有不同的签名。第二个参数接收一个表达式而不是一个委托。调用此方法的方法是:
DoSomethingExpression(names, p => p == "Alice");
这与我们在使用 lambda 创建匿名方法时所做的调用完全相同。这里的区别在于我们不是创建匿名方法,而是创建表达式树。正是由于这些表达式树,我们可以将 lambda 表达式转换为 SQL,例如 Linq 2 SQL 所做的,而不是在引擎中为每个子句(如 Where、Select 等)执行内容。是无论您是创建匿名方法还是发送表达式,调用语法都是相同的。