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>(); }
我意识到类型推断不是一门精确的科学,但我想知道是否有一些基本的“规则”我在这里缺失 – 我不熟悉规范的细节。
- 这是推理过程的缺点还是我期望编译器在这种情况下应该“弄明白”不合理(或许是歧义)?
- 我可以改变方法的签名,使其同样function但“可推断”吗?
我意识到类型推断不是一门精确的科学
我不确定我是否同意。 规范非常详细。
我想知道这里是否有一些基本的“规则”
您缺少的基本规则可能是约束不是签名的一部分。 类型推断取决于签名。
在我看来,这个设计决定的理由很充分。 然而,许多人认为我认为有充分理由做出设计决定,这在道德上是错误的。 如果你有兴趣阅读关于我是对还是错的主题的几百万字,请看我关于这个主题的文章和一百多条评论告诉我我错了:
这是推理过程的缺点吗?
可以,是的。 在我看来,根据竞争设计要求,这是一个合理的选择。 (那些“做用户意味着什么”和“当事情看起来模棱两可时给出错误”。)
我希望编译器在这种情况下应该“弄清楚”不合理吗?
不,你看起来像个合理的人,你的期望似乎是基于良好的推理。 但是,完全有可能有一个合理的期望,但仍未得到满足。 这将是其中一个案例。
我可以改变方法的签名,使其同样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
可以正常使用SomeMethod(new List
调用它SomeMethod(new List
。 我没有特别看到规范中涉及解决U = Ca
的类型的任何内容,因此可能没有定义该级别的推断。
为什么不省略IEnumerable的类型?
public static void SomeMethod (this IDictionary dict) where TValue : IEnumerable { }