Func<;T、 TResult>;委托真实世界使用

本文关键字:真实世界 TResult lt Func gt | 更新日期: 2023-09-27 17:58:19

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

MSDN上有一个他们执行以下操作的示例。。。

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

尽管它看起来很漂亮,是一个有趣的概念,但我看不出这样的代码提供了什么优势。

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

Func<;T、 TResult>;委托真实世界使用

如果你想问的是,我们通常有代表的原因:

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

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

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

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

您会在LINQ中大量使用它。例如,将列表中的所有数字加倍:

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

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

enemies.Select(x => tower.Location.DistanceTo(x.Location)).OrderBy(x => x).FirstOrDefault();

我认为懒惰初始化是一个很好的例子。

var value = new Lazy<int>(() => ExpensiveOperation()); // Takes Func<T>

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

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

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

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

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
});

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

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

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

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

Funct<T>的一个伟大用途,除了它嵌入在许多框架(如LINQ、Mocking Tools和依赖注入容器)中之外,就是使用它来创建一个基于委托的工厂。

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

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

然后,调用方代码只需要在字典中添加任意数量的条目,其中键是模式,值是该模式的替换字符串。我的方法在字典上循环,并为每个条目创建一个新的Func<string,string>。然后,对于每个小区,依次应用CCD_ 20。