【问题标题】:Func<T, TResult> delegate real world usesFunc<T, TResult> 委托现实世界使用
【发布时间】:2011-06-01 03:03:50
【问题描述】:

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

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

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

虽然它看起来很漂亮并且是一个有趣的概念,但我看不出这样的代码有什么优势。

那么这里有人可以提供他们必须使用Func&lt;T, TResult&gt; 的任何真实示例吗?一般来说,为什么人们可能想要使用这个委托?

【问题讨论】:

  • stackoverflow.com/questions/319789/… 能说明您的问题吗?
  • @Gabe:听起来他在问我们为什么需要代表,而不是为什么我们特别需要 Func&lt;T&gt;
  • 不,我绝对问我们为什么需要代表。我只是对我们为什么需要这个感到困惑。 @Gabe - 现在阅读这个问题。谢谢...
  • 在您的示例中,它是Func&lt;TIn, TOut&gt;,而不是Func&lt;T&gt;。你是指哪一个?请记住,Func 中的最后一个 T 始终是返回值。
  • 我指的是 Func - 将我的问题更新为更具体。 :-)

标签: c# lambda anonymous-function func


【解决方案1】:

如果您要问的,真的是我们有代表的原因:

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

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

如果您问为什么我们有 Func&lt;T, TResult&gt;(和类似的)代表,那么有两个主要原因:

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

【讨论】:

  • +1 "委托提供了一种将您自己的行为注入另一个对象的方法"
【解决方案2】:

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

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

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

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

【讨论】:

  • 略有不同 - 它说明了为什么 Func&lt;U,T&gt; 有用,而不是为什么/在哪里 Func&lt;T&gt; 有用。
  • @pst:这是问题的不一致 - 在代码示例中,他分配给 Func&lt;double, double&gt; 所以我认为这就是他的意思。
  • 这是对 linq 和 lambda 的绝佳使用。代码正式被盗! :-p PS: 为什么是 OrderBy(x => x) - 抱歉没明白这一点???
  • 哦,其实,我想我明白了……难道没有比 x => x 更好的表达方式吗?
  • @Maxim:不;按项目本身对可枚举进行排序需要该语法。
【解决方案3】:

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

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

【讨论】:

  • 对不起,我不明白你在那里做什么,有什么优势?我知道您将 lambda 传递给构造函数,但为什么呢?能否请您解释一下?
  • @Maxim:这里的目的是提供对初始化昂贵且可能不需要的对象的访问(或者最好推迟到以后)。这种语法允许您以类似于普通初始化器语法的方式定义对象,同时卸载昂贵的操作或根本不执行它。
  • 感谢您的解释。
【解决方案4】:

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

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

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

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

【讨论】:

    【解决方案5】:

    Func&lt;T&gt; 委托(和其他重载)为您提供了用 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'
    });
    

    【讨论】:

      【解决方案6】:

      首先,Func&lt;T&gt; 不是一个类,它是一个委托。

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

      【讨论】:

        【解决方案7】:

        Funct&lt;T&gt; 的一个很好的用途是使用它来创建delegate based factory

        【讨论】:

          【解决方案8】:

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

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-11-15
            • 1970-01-01
            相关资源
            最近更新 更多