C# 在F#中,默认情况下引用是否不可为空?

C# 在F#中,默认情况下引用是否不可为空?,c#,.net,f#,reference,C#,.net,F#,Reference,我知道在C语言中不是这样的,在Haskell这样的语言中也是这样(如果我没弄错的话),所以我想也许F在默认情况下也有相同的语义 而且,尽管它在C#中不存在,但它是语言的限制,而不是运行时,对吗?与F#或其他一些新的.NET语言一样,实际上可以将其作为默认值来实现,而无需使用任何类型的hack。在F#中,如果在F#代码中定义一个新类或其他类型,那么它在默认情况下是不可为空的,即 type MyClass() = ... ... let x : MyClass = null // does no

我知道在C语言中不是这样的,在Haskell这样的语言中也是这样(如果我没弄错的话),所以我想也许F在默认情况下也有相同的语义

而且,尽管它在C#中不存在,但它是语言的限制,而不是运行时,对吗?与F#或其他一些新的.NET语言一样,实际上可以将其作为默认值来实现,而无需使用任何类型的hack。

在F#中,如果在F#代码中定义一个新类或其他类型,那么它在默认情况下是不可为空的,即

type MyClass() = ...
...
let x : MyClass = null   // does not compile
然而,它将.NET IL代码编译为一个类,它是.NET上的一个引用类型,可以为null,因此C#可以创建该类型的null,甚至在F中#

让x:MyClass=Unchecked.defaultOf

会给你一个空值。因此,从这个意义上讲,这在很大程度上是“运行时的限制”-您永远无法创建一种既能“将类公开给C#,使其看起来像普通类”又能“确保该类型的实例永远不为null”的.NET语言。所以你必须在这里做出务实的决定。当你呆在F#内时,F#会试图防止你发生意外,避免处理null带来的麻烦,但如果你处理interop或.NET运行时细节,一天结束时null总是会出现。(十亿美元的错误。)

除了Brian提出的要点之外,可能值得一提的是,当您在F#中定义新类型时,您可以选择允许
null
值,如果这是您想要的行为。这是通过
AllowNullLiteral
属性完成的:

[<AllowNullLiteral>]
type T1() = class end

type T2() = class end

let t1 : T1 = null
let t2 : T2 = null // compiler error

选项类型与C#中的可空类型类似,只是它们不限于包装结构(以及一些与本主题无关的附加细微差异)。

如果您经常使用没有考虑到它的库,那么拥有这样一种语言功能本身并没有多大用处。在.NET4中使用代码契约对所有标准API进行注释可能会使更多地使用不可为空的引用成为可能。谢谢,我没有想到这一点。因此,如果库不是用它设计的,那么你在使用库时会遇到很多问题?谢谢,这篇文章很棒。对于其他.NET语言,我很惊讶他们不允许本机完成这项工作,并且在整个运行时都支持这项工作。你要么一开始就把这些东西弄对了,要么它太烤了,再也回不去换了。您可以在1999年构建一台时间机器,并尝试说服.NET/CLR人员相信这一点,但您可能会失败,因为他们当时有自己的一系列优先级。有些疣在整个过程成熟之前并不明显/疼痛。但这是进展的自然过程,希望下一个大型JVM/CLR/无论什么都能做到这一点,从第一天起就有泛型和不可为null的引用类型,然后一切都会变得轻松愉快。:)谢谢,那么这是通过属性完成的?但这是为类型本身,对吗?如果你有一个不能为null的类型,但是你说你想要它为null来表示某个值,那该怎么办?谢谢,像Maybe type这样的选项也是吗?选项对我来说似乎很奇怪,或者它的意思是可选中的选项?我想这是有道理的。同样在myFunc中,如果你忘记检查
o
None
,它会在编译时失败吗?@Joan-是的,F#(和ML家族中的其他语言)中的
选项
相当于Haskell中的
可能
。如果省略
None
案例,F#编译器将发出警告(而不是错误)。
[<AllowNullLiteral>]
type T1() = class end

type T2() = class end

let t1 : T1 = null
let t2 : T2 = null // compiler error
let myFunc (o:option<T2>) = 
  match o with
  | None -> "No value passed in"
  | Some(t2) -> "A T2 instance was passed in"