C# 中类型推断的优点和缺点是啥?

Posted

技术标签:

【中文标题】C# 中类型推断的优点和缺点是啥?【英文标题】:What are some advantages & disadvantages of type inference in C#?C# 中类型推断的优点和缺点是什么? 【发布时间】:2011-05-16 15:51:26 【问题描述】:

我有一个同事反对 C# 中的类型推断。我相信他的大部分论点都围绕着缺乏可读性。我反对这一点的论点是,Visual Studio 的智能感知功能提供了一种查看类型的简单方法,并且从代码中读取它们并不像我们在记事本中编码时那样必要。

但是,我很好奇在 C# 中使用类型推断的优缺点。我来自 C++,我知道 C++0x 的“自动”有一个更客观的好处,因为你并不总是知道你得到的类型(尤其是在进行繁重的模板编程时)。一个例子是使用 auto 来存储 Boost.Bind 的值。

在 C# 中,类型推断与其说是一项“很好拥有”或糖衣功能,不如说是一项要求。我认为当您处理长类型时它会很有用,例如:

Lazy<List<MyNamespace.ISomeVeryLongInterfaceType>> myVar = obj.GetLazy();

应该是:

var myVar = obj.GetLazy();

在我看来,这要干净得多。但是,是否有任何客观的论据支持 OR 反对类型推断?使用它是否是一种良好的编程习惯,即使在可以说它没有提供任何好处的情况下(例如,使用 'var' 而不是 'int')?

对于了解我应该如何在日常编码中使用“var”有一些帮助会很棒。

【问题讨论】:

ReSharper 似乎告诉我要经常使用var... 见blogs.msdn.com/b/ericlippert/archive/2011/04/20/… 好吧,如果你问我,明确命名类型应该是一个非常罕见的例外,即使这样,你也应该使用你可能负担得起的最通用类型。但话又说回来,我主要使用 Python(鸭子类型)进行编程,并且非常喜欢 Haskell(类型推断)和结构类型。 让我感到很有趣的是,每当出现这样的讨论时,示例中总是充斥着诸如myVarobj.GetLazy() 之类的毫无价值的名字。当你很好地命名变量时,一切似乎都是个坏主意。 【参考方案1】:

类型推断的发明正是您为 C++ 提供的原因,您可以创建没有类型名称的匿名类型(特别是 Lambdas 和 Linq)。

所以在这种情况下,它是必要的。

在另一种情况下(当类型名称已知时),则归结为样式。当类型非常明显时,我使用var

// I like this - less duplication and easier to read
var item = new List<ComplexObjectItem>();

代替:

List<ComplexObjectItem> item = new List<ComplexObjectItem>();

因为它减少了重复。

但是,当类型对读者来说不是很明显时,我不喜欢使用它:

// I don't like this - I need to look up what the type is
var item = ResultOfSomeFunctionWhereICantSeeWhatItIs();

但您的里程可能会有所不同。

【讨论】:

【参考方案2】:

我认为常识决定了以下非正式规则:

如果有一些长名称,例如:

Lazy<List<MyNamespace.ISomeVeryLongInterfaceType>> myVar = new Lazy<List<MyNamespace.ISomeVeryLongInterfaceType>>();

然后用

替换它
var myVar = new Lazy<List<MyNamespace.ISomeVeryLongInterfaceType>>();

有意义,因为您仍然可以分辨出对象是什么。

另一方面,一些模棱两可的东西可能保证不使用var

Lazy<List<MyNamespace.ISomeVeryLongInterfaceType>> myVar = doProcess();

【讨论】:

【参考方案3】:

隐式输入在某些情况下可能有用,而在其他情况下则有害。 Eric Lippert 最近在Uses and misuses of implicit typing 上发布了一篇值得一读的文章。

要记住一点,var 仅供用户使用,编译器在编译时将其转换为具体表示。

一个缺点是使用类中的接口时。

假设GetCurrentList() 返回一个IList&lt;string&gt;

IEnumerable<string> list = GetCurrentList();

var list = GetCurrentList();

与第二个示例不同,列表将是IList&lt;string&gt;

我倾向于使用显式类型,并且通常仅在有助于代码的可读性和使用匿名类型时使用var(因为此时您必须这样做)。

【讨论】:

【参考方案4】:

我喜欢使用类型推断来使代码更简洁,但是我只在可以看到它在同一行上的类型时才使用它,例如:

var myClass = new MyClass();

但是

MyClass myClass = RandomFuncThatGetsObject();

我认为在第一个示例中使用 var 不会影响可读性,实际上它使其更具可读性,但是在第二个示例中使用 var 会影响可读性。

【讨论】:

【参考方案5】:

当您使用匿名类型时,类型推断是必要的:

var x = new  Greeting = "Hello", Name = "World" ;

当您使用 LINQ 查询时,通常会一直使用匿名类型。

【讨论】:

【参考方案6】:
var myVar = obj.GetLazy();

在存在智能感知的情况下,这种类型推断大致是一个好主意,或者可以。但是,如果没有智能感知,那么我不会认为这是一个好主意。相反,这将是一场噩梦。如果没有智能感知,我相信大多数开发人员会不喜欢它,因为缺乏智能感知(以及精确类型,两者)造成的不便。

但是,即使没有智能感知,以下方法也不错:

var obj = new Lazy<List<MyNamespace.ISomeVeryLongInterfaceType>();

在这种情况下,类型推断是一种解脱,因为它可以避免大量输入和重复输入!

无论有没有智能感知,我都喜欢这样写:

Lazy<List<MyNamespace.ISomeVeryLongInterfaceType> obj= obj.GetLazy();

【讨论】:

即使使用 intellisense 也不清楚这里检索的是什么类型,如果有人可以看一下代码并知道发生了什么肯定会更好,如果在这样的方法中有 10 行代码您将不得不遍历每个对象并将鼠标悬停在发生这种情况的每一行上/启动智能感知 - 如果我不得不这样做,我会很生气

以上是关于C# 中类型推断的优点和缺点是啥?的主要内容,如果未能解决你的问题,请参考以下文章

如何让 C# 编译器自动推断这些类型参数?

C# 泛型方法类型参数不是从用法中推断出来的

如何知道 Spark 使用 Scala 推断出的 RDD 类型是啥

C#泛型对类型参数的推断

为啥 C# 无法从非泛型静态方法的签名推断泛型类型参数类型?

来自'??' 的 C# 类型推断(“var”)赋值空合并运算符