C# · 12月 24, 2021

c# – F#/ .NET null实例奇怪

我有这个C#DLL: namespace TestCSProject{ public class TestClass { public static TestClass Instance = null; public int Add(int a,int b) { if (this == null) Console.WriteLine(“this is null”); return a + b; } }}

而这个引用DLL的F#应用程序:

open TestCSProjectprintfn “%d” (TestClass.Instance.Add(10,20))

无人启动Instance静态变量.猜猜F#应用的输出是什么?

this is null30Press any key to continue . . .

经过几次测试,我发现除非我使用这个(例如访问实例字段),否则我不会得到NullReferenceExpcetion.

这是F#编译/ CLR中的预期行为还是间隙?

解决方法 我怀疑你会发现它正在使用call而不是callvirt,如果你看看IL. C#编译器始终使用callvirt,即使是非虚拟方法,因为它强制执行无效检查.

这是一个bug吗?嗯,不一定这取决于F#语言规范对空引用的方法调用的说明.它完全可以说,该方法将被称为(非虚拟),使用null“this”引用,这正是发生了什么.

C#碰巧指定这种取消引用将抛出NullReferenceException,但这是一种语言选择.

我怀疑F#方法可能会更快一点,因为缺乏无效检查涉及…并且不要忘记,空引用在F#中比在C#中更少的“预期”,这可能解释了采用的不同方法这里.或者它当然可以是一个监督.

编辑:我不是阅读F#规范的专家,但第6.9.6节至少对我来说,这是一个错误:

6.9.6 Evaluating Method Applications

For elaborated applications of methods,the elaborated form of the expression will be
either expr.M(args) or M(args).

The (optional) expr and args are evaluated in left-to-right order and the body of the member is evaluated in an environment with formal parameters that are mapped to corresponding argument values.

If expr evaluates to null then NullReferenceException is raised.

If the method is a virtual dispatch slot (that is,a method that is declared abstract) then the body of the member is chosen according to the dispatch maps of the value of expr.

无论这是否是一个精心设计的应用程序,都是有点超出我的,我害怕…但我希望这至少有一些帮助.