我想要写一个扩展方法,它可以处理那些值是某种序列的字典。不幸的是,编译器似乎无法从方法的使用中推断出泛型参数;我需要显式地指定它们。
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>>();
}我意识到类型推断并不是一门精确的科学,但我想知道是否有一些基本的“规则”我在这里遗漏了--我不熟悉规范的细节。
发布于 2010-10-19 16:01:47
更新:这个答案是十多年前写的;从那时起,类型推理规范和实现已经更新了好几次,包括在推理过程中使用约束的方式的更改。这个答案应该只考虑历史意义;请查阅C#规范的最新副本,以了解类型推断在当前实现中是如何工作的。
我意识到类型推断不是一门精确的科学
我不确定我同意。规格很详细。
我想知道是否有什么基本的“规则”我在这里错过了
您缺少的基本规则可能是约束不是签名的一部分。类型推断不受签名的影响。
在我看来,这个设计决定是有充分理由的。然而,许多人认为我在道德上是错误的,因为我认为有很好的理由做出这样的设计决定。如果你有兴趣阅读关于“我是对是错”这一主题的数百万字的文章,请看我关于这个主题的文章,以及关于我错的上百条评论:
这是推理过程的缺点吗?
可以说是的。在我看来,考虑到竞争的设计要求,这是一个合理的选择。(那些“按用户的意思去做”和“当事情看上去模棱两可时会出错”)。
在这种情况下,我认为编译器应该“找出”是不合理的吗?
不是的。你看起来是个通情达理的人,你的期望似乎是建立在良好的推理基础上的。然而,完全有可能有一个合理的期望,但仍未得到满足。这就是其中的一个案子。
我能不能改变方法的签名方式,使它同样的功能,但“地狱”?
这将是困难的,因为泛型字典类型在其转换中不是协变的或反变的。您想要捕获的概念在类型系统中很难以一种提供推断的方式表达。
如果您更喜欢使用具有更高级类型推断的语言,请考虑使用F#。如果您更喜欢偏向于“做用户所指的事情”的语言,而不是“报告歧义错误”,请考虑使用VB。
发布于 2010-10-19 13:37:08
C#类型推断不排除约束或返回值。所以你会有更好的运气
public static void SomeMethod<TKey, TUnderlyingValue>
(this IDictionary<TKey, IEnumerable<TUnderlyingValue>> dict)
{ }如果您将param声明为new Dictionary< string, IEnumerable<int>>(),而声明为new Dictionary<string, List<int>>(),则这将有效。
我不得不说,按照我阅读c#规范第7.5.2节的方式,似乎由于List<int>实现了IEnumerable<int>,TUnderlyingValue的类型推断应该能工作。然而,这一节并不是简单易懂的。我假设它不会在多个“层”中工作,因为SomeMethod<T>(IEnumberable<T> val){}在SomeMethod(new List<string>())中调用它很好。在规范中,我没有具体看到任何涉及解析U = Ca<Va, Cb<Vb>>类型的东西,因此可能没有定义该级别的推理。
发布于 2010-10-19 13:34:35
为什么不忽略IEnumerable的类型呢?
public static void SomeMethod<TKey, TValue>
(this IDictionary<TKey, TValue> dict)
where TValue : IEnumerable { } https://stackoverflow.com/questions/3968834
复制相似问题