【问题标题】:Implicit Type Inference only for lambda expressions ? Why ? Confused !隐式类型推断仅适用于 lambda 表达式?为什么 ?使困惑 !
【发布时间】:2010-12-07 18:36:04
【问题描述】:

我有以下示例代码(仅用于 C# 3.5 学习目的!)。

我正在调用接受 IEnumerable 和排序函数的排序函数。如果我使用 lambda 表达式(案例 A)调用它,编译器可以派生返回类型 TResult,但是当我传递 func SortInt(案例 B)时,编译器会抛出错误!

我无法理解为什么编译器无法在第二种情况下派生 TResult !我似乎传递了完全相同的信息。或者这不准确?

请帮忙!

int[] intArray = { 1, 3, 2, 5, 1 };

IEnumerable<int> intArray2 = Sort(intArray, x => SortInt(x)); // <= CASE A - OK !

IEnumerable<int> nextIntArray = Sort(intArray, SortInt); // <= CASE B - Compile Error: Cannot Infer Type !

public static IEnumerable<TResult> Sort<T, TResult>(IEnumerable<T> toBeSorted,    
                              Func<IEnumerable<T>, IEnumerable<TResult>> sortFunc)
{
    return sortFunc(toBeSorted);
}

public static IEnumerable<int> SortInt(IEnumerable<int> array)
{
    return array.OrderByDescending(x => x);
}

【问题讨论】:

  • 你的名字像印度人一样是印度人

标签: c# .net .net-3.5 lambda


【解决方案1】:

似乎在您的第二个示例中推理失败,因为编译器无法对 SortInt 执行重载解析。

这可能有助于更全面的解释:

http://blogs.msdn.com/ericlippert/archive/2007/11/05/c-3-0-return-type-inference-does-not-work-on-member-groups.aspx

【讨论】:

  • 那篇文章现在有些过时了;根据那篇文章的反馈,我们最终确实针对这类情况改进了类型推断算法。
  • 也就是说,是的,这仍然是在这种情况下我们未能进行重载解析的一个示例。
  • @罗伯特,谢谢!那篇文章正是针对这一点!
  • @Eric,谢谢你的文章!您是否写过一篇解释改进的新文章?那很好啊 !谢谢!
【解决方案2】:

我同意类型推断不适用于方法组转换,这很烦人。我希望 C# 编译器在组中只有一种适用方法的常见情况下更智能。但是,在复杂的情况下,您最终可能会遇到多个适用的重载,这会导致推断出不同的类型。

选项:

  • 从 lambda 表达式调用方法,如您所见
  • 明确指定类型参数,而不是依赖推理
  • 将方法组强制转换为所涉及的特定类型(比第二个选项差)
  • 使用单独的局部变量并明确指定其类型

基本上我会坚持前两个选项中的任何一个,尽管它们都很烦人。请注意,第一个选项会有轻微的性能损失,因为它是一个额外的间接级别,但这通常不会很重要。

【讨论】:

  • 感谢您的解释。我现在知道类型推断不适用于方法组!理解“为什么”对我来说并不是最简单的任务!
【解决方案3】:
IEnumerable<int> intArray = Sort(intArray, x => SortInt(x)); // <= CASE A - OK !

在此语句中,x =&gt; SortInt(x) 是如下代表:

delegate(IEnumerable<int> x){
    return SortInt(x);
}

从技术上讲,您没有在语句中的任何地方传递对 SortInt 的任何引用。

Func, IEnumerable> 是一个委托类型,这意味着它需要一个“指向函数的指针”,而不是函数。 SortInt 是一个方法。

如果你再深入一点,你会发现x =&gt; SortInt(x)的实际编译时表示如下:

private static IEnumerable<int> __XYZ(IEnumerable<int> x){
   return SortInt(x);
}

private delegate IEnumerable<int> __XYZHANDLER(IEnumerable<int> x);

你的第 1 行将是

IEnumerable<int> intArray = Sort(intArray, new __XYZHANDLER(__XYZ) );

现在查看您的第 2 行,SortInt 什么都不是,它是一个方法名称,它不是任何类型或实例。方法参数唯一可以具有的东西是某种类型的某个实例。 new Delegate 是方法指针的一个实例,而不是任何方法。

x =&gt; SortInt(x) 是上述所有内容的缩写形式,lambda 通常是编写匿名委托的较小形式,编译器不会将 SortInt 推断为 x =&gt; SortInt(x)

【讨论】:

    【解决方案4】:

    您的代码存在一些问题,导致其无法正常工作。

    首先,您的类型并不完全匹配。您将 int[] 作为 IEnumerable 传递,但如果不调用 .AsEnumerable(),则无法执行此操作。

    其次,T 和 TResult,虽然用法相同,(int),但对编译器来说是不一样的,但是你传入一个 int 数组并期望一个 IEnumerable 而没有说明结果的类型是什么.因此,您必须将 TResult 的类型与您的版本一起传递(例如 Sort(intArray.AsEnumerable(), SortInt)),这可以工作,但您不需要 TResult,因为您只是订购了相同的类型,T.

    所以,我摆脱了 TResult 并修复了类型:

    void Main() 
    {
      var intArray = new [] { 1, 3, 2, 5, 1 };
      var ints = Sort(intArray.AsEnumerable(), x => SortInt(x)); 
      var nextInts = Sort(intArray.AsEnumerable(), SortInt); 
    }
    
    public static IEnumerable<T> Sort<T>(
                  IEnumerable<T> toBeSorted, 
                  Func<IEnumerable<T>, IEnumerable<T>> sortFunc) 
    {        
       return sortFunc(toBeSorted);
    }
    
    public static IOrderedEnumerable<T> SortInt<T>(IEnumerable<T> array) 
    {    
        return array.OrderByDescending(x => x);
    }
    

    我更喜欢上面的方法,但是,这是我能找到的最接近您的示例的方法,并且有效:

      void Main() {
        var intArray = new [] { 1, 3, 2, 5, 1 };
        var ints = Sort(intArray.AsEnumerable(), x => SortInt(x)); 
        var nextInts = Sort<int, int>(intArray.AsEnumerable(), SortInt); 
       }
    
       public static IEnumerable<TResult> Sort<T, TResult>(
                     IEnumerable<T> toBeSorted, 
                     Func<IEnumerable<T>, IEnumerable<TResult>> sortFunc)
       {    
          return sortFunc(toBeSorted);
       }
       public static IEnumerable<int> SortInt(IEnumerable<int> array){    
          return array.OrderByDescending(x => x);
       }
    

    SortInt 也可以是:

    public static IOrderedEnumerable<T> SortInt<T>(IEnumerable<T> array){    
       return array.OrderByDescending(x => x);
    }
    

    Akash 解释了为什么在使用 lambda 表达式时会有所不同。

    【讨论】:

      猜你喜欢
      • 2015-09-22
      • 1970-01-01
      • 2019-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多