7

我最近一直在玩委托Func<T, TResult>,并创建返回Func<T, TResult>包含 lambda 的不同实例的方法,但我一直在努力想出的是关于为什么人们可能想要返回(甚至创建这样的实例)的任何好的现实世界想法。

在MSDN上有一个示例,他们执行以下操作...

Func<string, string> convertMethod = UppercaseString;
private static string UppercaseString(string inputString)
{
    return inputString.ToUpper();
}

尽管它看起来很漂亮并且是一个有趣的概念,但我看不到这样的代码提供了哪些优势。

那么这里有人可以提供他们必须使用Func<T, TResult>的任何现实世界的例子吗?一般来说,为什么人们可能想要使用这个代表?

4

8 回答 8

12

如果您真正要问的是为什么我们一般都有代表:

  • 如果您曾经消费过一个事件,那么您就使用过委托
  • 如果您曾经使用过 LINQ,那么您就使用过委托(从技术上讲,对于IQueryable提供程序,您使用过表达式,但对于 LINQ-to-Objects,您使用过委托)

委托提供了一种将您自己的行为注入另一个对象的方法。最常见的用法是事件。一个对象公开一个事件,您提供一个函数(匿名或非匿名),该函数在该事件触发时被调用。

如果你问为什么我们有Func<T, TResult>(和类似的)委托,那么有两个主要原因:

  1. 当人们在他们的代码中需要一个特定的委托时,他们不得不声明他们自己的简单委托类型。虽然Action<>Func<>委托不能涵盖所有情况,但它们很容易提供并涵盖了许多需要自定义委托的情况。
  2. 更重要的是,Func<T, TResult>委托在 LINQ-to-Objects 中广泛用于定义谓词。更具体地说,Func<T, bool>. 这允许您定义一个谓词,该谓词接受 an 的强类型成员IEnumerable<T>并使用 lambda 或普通函数返回布尔值,然后将该谓词传递给 LINQ-to-Objects。
于 2011-06-01T03:06:42.003 回答
4

你会在 LINQ 中经常使用它。因此,例如,将列表中的所有数字加倍:

myList.Select(x => x * 2);

那是一个Func<TIn, TOut>。在创建简洁的代码时非常有用。一个真实的例子是在我制作的众多塔防游戏之一中,我使用一条线计算了离塔最近的敌人:

enemies.Select(x => tower.Location.DistanceTo(x.Location)).OrderBy(x => x).FirstOrDefault();
于 2011-06-01T03:06:23.500 回答
3

我认为一个很好的例子是延迟初始化。

var value = new Lazy<int>(() => ExpensiveOperation()); // Takes Func<T>
于 2011-06-01T03:07:40.130 回答
3

需要函数指针的典型示例是将比较函数传递给排序例程。为了有不同的排序键,您为比较函数创建一个 lambda,并将其传递给排序函数。

或者对于一个简单的现实世界的例子:

IEnumerable<Person> FindByLastName(string lastName)
{
    return Customers.Where(cust => cust.LastName == lastName);
}

在这个例子中,cust => cust.LastName == lastName不仅仅是一个 lambda,而是通过捕获lastName参数来创建一个闭包。换句话说,它创建了一个函数,每次FindByLastName调用都会有所不同。

于 2011-06-01T03:12:52.427 回答
2

Func<T>委托(和其他重载)为您提供了在 C# 中编写抽象的新方法。为了演示一些选项,这里有几个可以使用委托编写的 C# 语言结构:

Thread.Lock(obj, () => { 
    // Safely access 'obj' here
});

Enumerable.ForEach(collection, element => {
    // Process 'element'
});

Exceptions.Try(() => { 
    // Try block
}).With((IOException e) => {
    // Handle IO exceptions
});

这些都是相当原始的,所以最好为它们有一个语言结构。然而,它证明了Funclambda 表达式增加了相当多的表达能力。它可以编写新的结构,例如并行循环(使用 .NET 4.0):

Parallel.ForEach(collection, element => {
    // Process 'element'
});
于 2011-06-01T03:14:30.243 回答
1

首先,Func<T>不是一个类,它是一个委托。

基本上,如果您不想为此声明自己的委托,则可以在需要方法参数或委托类型的属性时使用它。

于 2011-06-01T03:10:02.423 回答
1

Funct<T>除了嵌入在许多框架(例如 LINQ、Mocking Tools 和 Dependency Injection 容器中)之外,它的一个很好的用途是使用它来创建基于委托的工厂

于 2011-06-01T03:17:38.700 回答
0

最近,我希望调用我的方法的外部程序能够修改它的行为方式。

我的方法本身只是将文件从 XLS 转换为 XML。但是有必要允许调用代码在需要时指定任意数量的转换,这些转换应在写入为 xml 标记之前应用于每个 xls 单元格。例如:将“,”小数分隔符转换为“.”,取消千位分隔符,等等(转换都是字符串替换)。

然后调用者代码只需在字典中添加任意数量的条目,其中键是模式,值是该模式的替换字符串。我的方法循环遍历字典并Func<string,string>为每个条目创建一个新的。然后对于每个单元格按Func<string,string>顺序应用。

于 2011-06-01T08:13:58.820 回答