代码之家  ›  专栏  ›  技术社区  ›  Ani

泛型:在这种情况下,编译器为什么不能推断类型参数?

  •  8
  • Ani  · 技术社区  · 14 年前

    public static void SomeMethod<TKey, TUnderlyingValue, TValue>
        (this IDictionary<TKey, TValue> dict)
        where TValue : IEnumerable<TUnderlyingValue> { }    
    
    static void Usage()
    {
        var dict = new Dictionary<int, string[]>();
        var dict2 = new Dictionary<int, IEnumerable<string>>();
    
        //These don't compile
        dict.SomeMethod();
        SomeMethod(dict); // doesn't have anything to do with extension-methods
        dict2.SomeMethod(); // hoped this would be easier to infer but no joy
    
    
        //These work fine
        dict.SomeMethod<int, string, string[]>();
        dict2.SomeMethod<int, string, IEnumerable<string>>();
    }
    

    我意识到类型推断并不是一门精确的科学,但我想知道这里是否遗漏了一些基本的“规则”——我不熟悉规范的细节。

    1. 这是推理过程的一个缺点还是我期望编译器在这种情况下应该“找出它”是不合理的(可能是模棱两可的)?
    2. 我可以改变方法的签名,使其功能相同,但“不可推断”吗?
    3 回复  |  直到 14 年前
        1
  •  16
  •   Eric Lippert    14 年前

    我知道类型推理不是一门精确的科学

    我不确定我是否同意。规格相当详细。

    我想知道我是否遗漏了一些基本的“规则”

    您缺少的基本规则可能是约束不是签名的一部分。类型推断从签名开始工作。

    我认为这项设计决定有充分的理由。然而,很多人认为我认为有充分的理由做出设计决定,这在道德上是错误的。如果你有兴趣阅读关于我是对是错这一主题的几百万字,请看我关于这一主题的文章和数百条左右的评论,告诉我我错了:

    http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx

    这是推理过程的缺点吗?

    在这种情况下,我期望编译器应该“找出它”是否不合理?

    不。你看起来是个通情达理的人,你的期望似乎是基于良好的推理。然而,完全有可能有一个合理的预期,但没有得到满足。这就是其中之一。

    这将很困难,因为泛型字典类型在其转换中不是协变或反变的。要捕获的概念在类型系统中不容易以提供推断的方式表示。

    如果您喜欢使用具有更高级类型推断的语言,请考虑使用F。如果你更喜欢倾向于“按照用户的意思去做”而不是“在歧义上报告错误”的语言,可以考虑使用VB。

        2
  •  4
  •   Philip Rieck    14 年前

    C#类型推断不能脱离约束或返回值。所以你会 轻微地 祝你好运

    public static void SomeMethod<TKey, TUnderlyingValue>
        (this IDictionary<TKey, IEnumerable<TUnderlyingValue>> dict)
      { }
    

    如果您将参数声明为 new Dictionary< string, IEnumerable<int>>() ,但是 如果你申报 new Dictionary<string, List<int>>() .

    c# spec ,似乎从 List<int> 工具 IEnumerable<int> ,的类型推断 TUnderlyingValue 应该有用。然而,这一部分并不完全容易理解。我认为它不能通过多个“层”工作,因为 SomeMethod<T>(IEnumberable<T> val){} 打电话给他就行了 SomeMethod(new List<string>()) . 我在规范中没有特别看到任何处理解析类型 U = Ca<Va, Cb<Vb>> ,因此,可能未定义该级别的推理。

        3
  •  1
  •   Pieter van Ginkel    14 年前

    为什么不省略IEnumerable的类型呢?

    public static void SomeMethod<TKey, TValue>
    (this IDictionary<TKey, TValue> dict)
    where TValue : IEnumerable { }