隐式类型转换:为什么只局限于本地变量?

25

有人知道或者愿意推测为什么隐式类型声明只限于局部变量吗?

var thingy = new Foo();

但为什么不呢?...

var getFoo() {
    return new Foo(); 
}
6个回答

43

有意思,他建议添加另一个功能来弥补编译器的不足。有方法可以编写编译器,不允许匿名类型泄漏出来,或者可以处理延迟第一次通行的方法。 - Sam Saffron
5
我知道有方法可以做到这一点,但我们目前选择不采取任何一种方法;因为它们的成本并不值得其所带来的好处。 - Eric Lippert
抱歉Eric,我想说的是,与其投票复制Java的new()方法,即使我们可以更快地获得它,我很高兴等待编译器重构。因为它似乎不太合适,既然我们已经有了var。 - Sam Saffron
7
同时,针对字段定义进行的一种非常受限的类型推断版本可以实现99%的效果(在我看来)......只支持var dict = new Dictionary<int,int>(); 不支持通过方法初始化的var字段。 - Sam Saffron

7

Jared在他的回答中提供了一个很棒的链接,涉及到一个很棒的话题。

我认为它没有明确回答问题。

为什么呢?

var getFoo() {
    return new Foo(); 
}

这是因为: 如果发生什么事情呢?
class Foo {}

var GetFoo() {
   return GetBar(); 
}

var GetBar() {
  return GetBaz(); 
}

var GetBaz() {
   return new Foo();
}

你可以推断出GetFoo将返回Foo,但你必须跟踪该方法所做的所有调用及其子调用,才能推断出类型。就目前而言,C#编译器并不是以这种方式设计的。在代码推断类型运行之前,它需要早期的方法和字段类型。
从纯美学角度来看,我认为方法中var定义会使事情变得混乱。这是我认为明确表达总是有帮助的一个地方,它可以保护你免受意外返回导致签名和大量其他依赖方法签名发生变化的类型的伤害。更糟糕的是,如果你返回一个返回对象的方法的值,并且碰巧很幸运,你甚至可能在不知情的情况下更改方法链的所有签名。
我认为var方法最适合像Ruby这样的动态语言。

12
不,那不是问题所在。正如你可以展示的那样,我们已经在C#中解决了那个问题。如果你将getFoo变成lambda表达式,我们将推断lambda表达式的返回类型为Foo。然而,还存在一个真正的问题。一个问题是,如果“var getFoo(){...}”调用“var getBar(){...}”,后者又调用...你最终可能需要进行全程序分析才能对方法进行类型化。当前编译器架构假定在分析方法体之前可以对方法和字段进行类型标记。 - Eric Lippert
更正和扩展答案以反映 - Sam Saffron

1

你可以在 VS 2010 中使用动态

Dynamic getFoo() { 
    return new Foo();  
} 

除非你真的无法在那里写出类型(例如匿名类型),否则这是避免编写长类型名称的可怕方式。你会放弃静态绑定带来的所有(相当可观的)好处。 - Ethan Reesor
但它是小写的“动态”。 - Arturo Torres Sánchez
这太有帮助了!这解决了我需要通过初始化程序推断字段类型的所有明显情况,这对我来说很多。Eric L.在他解释为什么字段没有var的论文开头就说了同样的话。他的论文继续解释了极端递归情况是一个问题,但我无法理解为什么更常见的情况没有得到解决。幸运的是,“dynamic”解决了这个问题。 - Gabe Halsmer
@GabeHalsmer dynamicvar 不同。var 在编译时推断类型,而 dynamic 根据分配的内容在运行时进行类型定义。 - bazzilic
我同意,动态类型并不像一开始看起来那么好。我忘记了我遇到了什么限制,但我无法利用它。这让我想起了匿名类型,一开始看起来非常有用。但它也有限制。我记得有十几次我认为我可以使用匿名类型,只能因为这些限制而不得不将其删除(例如,逻辑需要移入命名函数中 - 无法传递匿名类型)。 - Gabe Halsmer

1

因为这样做要简单得多。如果您要进行所有类型的推断,那么需要类似 Hindley Milner 类型推断系统的东西,这将使您所钟爱的 C# 成为 Haskel 衍生语言。


1

实际上,你遇到的问题是C#(目前)是一种静态类型语言。定义为var的局部变量仍然是静态类型,但在语法上被隐藏了。另一方面,返回var的方法有许多含义。它变得更像一个用法接口,使用var并没有任何好处。


0

我认为这是因为隐含类型的范围更广,因此比单个方法的范围更容易引起问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接