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

我想写一个扩展方法,它可以用于字典,它的值是某种顺序。 不幸的是,编译器似乎无法从我对该方法的使用中推断出generics参数; 我需要明确指定它们。

public static void SomeMethod (this IDictionary dict) where TValue : IEnumerable { } static void Usage() { var dict = new Dictionary(); var dict2 = new Dictionary<int, IEnumerable>(); //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(); dict2.SomeMethod<int, string, IEnumerable>(); } 

我意识到类型推断不是一门精确的科学,但我想知道是否有一些基本的“规则”我在这里缺失 – 我不熟悉规范的细节。

  1. 这是推理过程的缺点还是我期望编译器在这种情况下应该“弄明白”不合理(或许是歧义)?
  2. 我可以改变方法的签名,使其同样function但“可推断”吗?

我意识到类型推断不是一门精确的科学

我不确定我是否同意。 规范非常详细。

我想知道这里是否有一些基本的“规则”

您缺少的基本规则可能是约束不是签名的一部分。 类型推断取决于签名。

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

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

这是推理过程的缺点吗?

可以,是的。 在我看来,根据竞争设计要求,这是一个合理的选择。 (那些“做用户意味着什么”和“当事情看起来模棱两可时给出错误”。)

我希望编译器在这种情况下应该“弄清楚”不合理吗?

不,你看起来像个合理的人,你的期望似乎是基于良好的推理。 但是,完全有可能有一个合理的期望,但仍未得到满足。 这将是其中一个案例。

我可以改变方法的签名,使其同样function但“可推断”吗?

这很难,因为通用的Dictionary类型在其转换中不是协变的或逆变的。 您想要捕获的概念不容易在类型系统中以提供推理的方式表达。

如果您更喜欢使用具有更高级类型推断的语言,请考虑使用F#。 如果您更喜欢倾向于“做用户意味着什么”而不是“报告模糊错误”的语言,请考虑使用VB。

C#类型推断不受约束或返回值的影响。 所以你运气好一点

 public static void SomeMethod (this IDictionary> dict) { } 

如果您将param声明为new Dictionary< string, IEnumerable>() ,这将有效,但如果您将其声明为new Dictionary>()不会

我不得不说,就像我阅读c#规范第7.5.2节的方式一样,似乎由于List实现了IEnumerable ,所以TUnderlyingValue的类型推断应该有效。 但是,该部分并不是很容易理解的。 我认为它不能通过多个“层”工作,因为SomeMethod(IEnumberable val){}可以正常使用SomeMethod(new List())调用它SomeMethod(new List()) 。 我没有特别看到规范中涉及解决U = Ca>的类型的任何内容,因此可能没有定义该级别的推断。

为什么不省略IEnumerable的类型?

 public static void SomeMethod (this IDictionary dict) where TValue : IEnumerable { }