首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >泛型:在这种情况下,为什么编译器不能推断类型参数?

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

Stack Overflow用户
提问于 2010-10-19 13:27:33
回答 3查看 1.9K关注 0票数 8

我想要写一个扩展方法,它可以处理那些值是某种序列的字典。不幸的是,编译器似乎无法从方法的使用中推断出泛型参数;我需要显式地指定它们。

代码语言:javascript
复制
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. 我能不能改变方法的签名方式,使它同样的功能,但“地狱”?
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2010-10-19 16:01:47

更新:这个答案是十多年前写的;从那时起,类型推理规范和实现已经更新了好几次,包括在推理过程中使用约束的方式的更改。这个答案应该只考虑历史意义;请查阅C#规范的最新副本,以了解类型推断在当前实现中是如何工作的。

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

我不确定我同意。规格很详细。

我想知道是否有什么基本的“规则”我在这里错过了

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

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

https://learn.microsoft.com/en-us/archive/blogs/ericlippert/constraints-are-not-part-of-the-signature

这是推理过程的缺点吗?

可以说是的。在我看来,考虑到竞争的设计要求,这是一个合理的选择。(那些“按用户的意思去做”和“当事情看上去模棱两可时会出错”)。

在这种情况下,我认为编译器应该“找出”是不合理的吗?

不是的。你看起来是个通情达理的人,你的期望似乎是建立在良好的推理基础上的。然而,完全有可能有一个合理的期望,但仍未得到满足。这就是其中的一个案子。

我能不能改变方法的签名方式,使它同样的功能,但“地狱”?

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

如果您更喜欢使用具有更高级类型推断的语言,请考虑使用F#。如果您更喜欢偏向于“做用户所指的事情”的语言,而不是“报告歧义错误”,请考虑使用VB。

票数 16
EN

Stack Overflow用户

发布于 2010-10-19 13:37:08

C#类型推断不排除约束或返回值。所以你会有更好的运气

代码语言:javascript
复制
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>>类型的东西,因此可能没有定义该级别的推理。

票数 4
EN

Stack Overflow用户

发布于 2010-10-19 13:34:35

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

代码语言:javascript
复制
public static void SomeMethod<TKey, TValue>
(this IDictionary<TKey, TValue> dict)
where TValue : IEnumerable { }    
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3968834

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档