为什么C#可以检查'var'是否为空?

3

I have the following code:

List<IMessage> messageList = new List<IMessage>();

foreach(var msg in messageList)
{
    if(msg != null)
    {

    }
}

如何检查var msg是否为null?编译器如何知道var是一个IMessage而不是一个int或其他不可空类型?如果您查看MSDN上的示例,它们会为隐式类型变量提供初始值(从而使声明变为显式)。在我的情况下,我甚至没有给它赋值,但编译器没有问题。编译器如何知道msg是可空的?

6
你的 messageList 是一个类型为 IMessage 的项目列表,因此编译器可以轻松地推断出 msg 的实际类型为 IMessage。如果编译器无法推断类型,则无法使用 var - 例如 var msg; 将不被允许。 - stuartd
顺便提一下,无论如何都可以将一个值与 null 进行比较。如果 msg 是一个 int,编译器会发出警告,因为比较总是为 true,但它不会被禁止。 - Jeroen Mostert
@JeroenMostert 当我将null与值类型进行比较时,我会得到更多的警告。不确定你在说什么。 - Snoop
我想说的是 var i = 5; Console.WriteLine(i != null) 会产生 CS0472 错误。你可能已经将警告配置为错误。 - Jeroen Mostert
@JeroenMostert 你说得对,我确实是这样配置的,而且我不知道这很有趣。我知道检查值类型的 null 是没有意义的,因为它们不可为空,所以我猜我从来没有尝试过。 - Snoop
总的来说,它并不是没有意义的:如果 bool f<T>(T t) { return t != null; } ,那么 Console.WriteLine(f(5)) 将会在编译时没有警告。从概念上讲,在 C# 中的所有东西都是对象,因此允许将其与 null 进行比较。发出警告是因为在这个特定的情况下,比较结果总是相同的。 - Jeroen Mostert
5个回答

4
编译器知道msg是可空的,因为它是静态类型。静态类型是IMessage,即使您没有命名它。
编译器把IMessage换成了var的原因是,它出现在foreach (var identifier in collection )中,而collection是一个实现了IEnumerable<IMessage>接口的类型表达式。
每个var出现都会被静态地替换为某种类型。(虽然也可能是动态的,但dynamic不是默认值,只有在静态类型推断规则下可以推断时才能应用)如果静态类型推断规则找不到要替换的唯一类型,则不允许使用该var

1

var是一个非常具有误导性的关键词。
var声明具有特定数据类型的变量,而不告诉程序员该类型是什么。

实际上声明的是什么

 foreach (IMessage msg in messageList)

但这是你自己要解决的问题。

0
编译器为您推断类型。在基本级别上,当您说:
var x = "foo";

编译器看到表达式的右侧是一个字符串,就会将类型分配给x。
当编译器遇到foreach语句时也不会有任何不同。它确定了IEnumerable类型(在您的情况下为IEnumerable ),并将msg分配为IMessage类型。

0
在你的例子中,你的messageListList<IMessage>类型,因此,当你执行以下操作时:

foreach (var m in messageList)

C#自动知道要期望什么类型的项(在你的列表中包含的那些,在这个例子中是IMessage对象),并且在编译时推断出var将被翻译为IMessagevar关键字只是语法糖,它实际上不是一种类型。它只是让你的生活更轻松(你不必写实际类型)。

0

var 的类型在编译时总是已知的。任何无法从语法中推断出类型的情况都会造成编译时错误。

在这种情况下,您正在遍历一个 IMessage 类型的集合,因此编译器知道迭代变量的类型为 IMessage,因此可为空。


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