9

我一直在 VS2008 ( http://msdn.microsoft.com/en-us/devlabs/dd491992.aspx )上玩代码合同。
它们肯定很好,并且为方法内部的 if-then-throw 检查提供了可靠的替代方案。

尽管如此,我一直希望它们能够满足我强烈认为不可为空的引用类型的需求。
唉,据我所见,情况似乎并非如此。
这是我的理解:

  • 这样的事情仍然会在运行时引起问题:
    MyClass a = null;
    a.ToString();

  • 我仍然必须明确地编写检查,即使是以更简洁和流线型的方式。

  • 除非您使用 VS Team System,否则您只能在运行时使用代码契约来检查事物,在编译时没有任何好处。
    这意味着当出现问题时,您仍然必须处理事情。
    与处理简单的异常没有太大区别。

  • 即使使用 VSTS 静态分析也不如在运行时完成的那样好。
    这是完全可以理解的,但它仍然是此功能适用于运行时使用的另一个迹象。

如果我错了,请纠正我,但据我所知,代码合同无法让我的生活更轻松,我的程序更健壮,就像不可为空的引用类型一样。

不要误会我的意思,我不喜欢代码合同。
它们是对整个框架的一个非常好的增强。
只是如果这不能填补 C# 由于没有不可为空的引用类型而留下的空白,那么在这一点上恐怕什么都不会。
你怎么看?

4

5 回答 5

20

我认为你对此是正确的。编译时不可为空的引用检查是我在代码合同中等待的杀手级功能,但它实际上并不存在。

对于那些想知道这意味着什么的人,可以考虑与值类型进行类比。它们最初不可为空,但现在如果您在类型名称后加上问号,它们就可以了:

int? n;

为了一致性,如果引用类型也是如此,那将是理想的。但这会破坏所有现有的 C# 程序,因此不是一个选择。在研究语言Spec#中,他们使用感叹号后缀表示不可为空:

string! s = "Hello";

与普通值类型一样,编译器在初始化之前静态检查string!变量是否未在任何代码路径上使用(我相信 Spec# 要求在同一语句中进行声明和初始化)。

它还禁止null对该变量的赋值。

当然,它禁止将普通分配stringstring!. 那么如何弥合这两种类型之间的鸿沟呢?通过写支票:

string x = GetStringFromSomewhere();

if (x != null)
    s = x; // okay because compiler sees null check

可悲的事实是,如果程序是正确的,大多数程序中的大多数参考变量都可能是不可为空的。可空变量是少数。然而,它们是默认值。

1960 年代的另一个坏主意

于 2009-10-04T10:19:09.163 回答
3

我不确定“不可为空的引用类型”解决了什么问题。好的,所以这段代码不太可能引发异常:-

a.ToString();

但是,它不再可能是正确的,因为它不可为空吗?的初始值是a多少?可能是该类型的一些默认“空”实例。在那种情况下,它不是更有可能使事情更难以调试,因为应该已经分配了值的值没有。只是有一些默认行为而不是导致异常听起来不像我想要的。

于 2009-10-01T09:39:39.980 回答
3

我认为不可为空引用类型的概念对于映射到数据库字段的 ORM 生成的属性非常有用。通常,您无法从属性(通常是字符串类型)判断基础字段是否可以为空。您可以使用可为空的值类型,只需查找问号即可。

我不太担心静态检查,除了明显的 foo! =空;失败了,但我认为智能感知作为可变意图的提示将非常有用。

于 2010-08-19T02:50:08.293 回答
0

编译时不可为空的引用检查是我在代码合同中等待的杀手级功能,但它实际上并不存在。

2017 年更新(8 年后),虽然不可为空的引用类型仍然不存在......可空的引用类型可能。

Mads Torgersen (Microsoft 的 C# 语言 PM)在这条推文中确实提到了它:

可空引用类型的原型终于来了!

这在“ C# 中的可空引用类型简介”和本视频“ C# 7.1 和 7.2 可用的新功能”中有详细说明。

如果我们只添加一种新的“安全”引用类型,然后将现有引用类型重新解释为另一种“安全”类型,则可以实现这一点。更具体地说,我们认为无注释引用类型(如字符串)的默认含义应该是不可为空的引用类型,原因如下:

我们认为,希望引用不为空更为常见。可以为空的引用类型将是较少见的类型(尽管我们没有好的数据可以告诉我们多少),因此它们应该需要新的注释。该语言已经有了可空值类型的概念和语法。两者之间的类比将使语言添加在概念上更容易,并且在语言上更简单。
除非您已经主动决定想要它们,否则您不应该用繁琐的 null 值给自己或您的消费者带来负担,这似乎是正确的。Nulls,而不是没有它们,应该是您明确必须选择加入的东西。
这是它的样子:

class Person
{
    public string FirstName;   // Not null
    public string? MiddleName; // May be null
    public string LastName;    // Not null
}

这个类现在能够表达每个人都有名字和姓氏的意图,但只有一些人有中间名。

因此,我们找到了将这种语言特性称为“可空引用类型”的原因:那些是添加到语言中的。不可为空的已经存在,至少在语法上是这样。

这仍然是一个原型,并且可能最终(或不)在语言中。在“ C# 可空引用类型预览
”中 查看更多信息。

于 2017-11-16T21:12:24.473 回答
-2

而不是使用 null 您可以使用默认值,例如 string.empty 不需要空值

于 2009-11-02T03:08:01.983 回答