C# NET 4.0中的代码契约,不可为空的引用类型没有乐趣?

C# NET 4.0中的代码契约,不可为空的引用类型没有乐趣?,c#,.net,.net-4.0,c#-4.0,code-contracts,C#,.net,.net 4.0,C# 4.0,Code Contracts,我一直在玩VS2008()上的代码契约。 它们当然很好,并且提供了一个可靠的替代方法,可以替代if-then在方法内部抛出检查 尽管如此,我一直希望它们能够满足我强烈感受到的不可空引用类型的需求。 唉,据我所知,情况似乎并非如此。 这就是我所理解的: 类似的内容在运行时仍会导致问题: MyClass a=null a、 ToString(); 我仍然必须明确地写支票,即使是以更简洁、更精简的方式 除非您使用VS Team System,否则您只能在运行时使用代码契约进行检查,在编译时没有任

我一直在玩VS2008()上的代码契约。
它们当然很好,并且提供了一个可靠的替代方法,可以替代if-then在方法内部抛出检查

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

  • 类似的内容在运行时仍会导致问题:
    
    MyClass a=null
    a、 ToString();

  • 我仍然必须明确地写支票,即使是以更简洁、更精简的方式

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

  • 即使使用VSTS,静态分析也不如在运行时进行的分析好。
    这是完全可以理解的,但这是另一个迹象,表明此功能是用于运行时使用的

如果我错了,请纠正我,但从我所看到的情况来看,代码契约无法让我的生活更轻松,我的程序更健壮,就像不可为null的引用类型一样

别误会,我并不讨厌代码契约。
它们是对整个框架的很好的增强。
只是如果这不能通过不可为空的引用类型来填补C#留下的空白,那么在这一点上,恐怕什么都不会
你觉得怎么样?

我不确定“非空引用类型”解决了什么问题。好的,那么这段代码抛出异常的可能性要小得多:-

a.ToString();

但是,它是否仍然可能是正确的,因为它不可为空?
a
的初始值是多少?可能是该类型的某个默认“空”实例。在这种情况下,是不是会使调试变得更加困难,因为应该分配值的值还没有被分配。仅仅拥有一些默认行为而不是导致异常听起来不像我想要的东西。

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

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

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

string! s = "Hello";
与普通值类型一样,编译器静态检查
字符串
变量在初始化之前不会在任何代码路径上使用(我相信Spec#要求在同一语句中进行声明和初始化)

它还禁止将
null
赋值给该变量

当然,它禁止将普通的
字符串
赋值给
字符串。那么,如何弥合这两种类型之间的差距呢?通过开支票:

string x = GetStringFromSomewhere();

if (x != null)
    s = x; // okay because compiler sees null check
可悲的事实是,如果程序是正确的,那么大多数程序中的大多数参考变量都可能是不可为空的。可为空的变量占少数。但它们是默认的


!

您可以使用类似字符串的默认值,而不是使用null。empty不需要null

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

我不太担心静态检查,除了明显的foo!=无效的失败了,但我认为intellisense作为变量意图的提示非常有用

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

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

(微软的C#语言PM)确实提到了这一点:

可空引用类型的原型终于出现了

这在“”和本视频“”中有详细说明

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

我们认为,希望引用不为空更为常见。可为空的引用类型将是比较少见的类型(尽管我们没有好的数据来告诉我们有多少),因此它们应该需要一个新的注释。 该语言已经有了可空值类型的概念和语法。两者之间的类比将使语言添加在概念上更容易,在语言上更简单。
似乎你不应该给自己或你的消费者带来麻烦的空值,除非你已经主动决定想要它们。空值,而不是没有空值,应该是您必须明确选择的对象。
下面是它的样子:

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

因此,我们找到了将这种语言特性称为“可空引用类型”的原因:这些类型是添加到语言中的类型。不可为空的o
class Person
{
    public string FirstName;   // Not null
    public string? MiddleName; // May be null
    public string LastName;    // Not null
}