F#/ .NET null实例奇怪

Ele*_*tik 9 .net c# f#

我有这个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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这个引用DLL的F#app:

open TestCSProject
printfn "%d" (TestClass.Instance.Add(10,20))
Run Code Online (Sandbox Code Playgroud)

没有人启动Instance静态变量.猜猜F#app的输出是什么?

this is null
30
Press any key to continue . . .

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

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

Jon*_*eet 10

我怀疑你会发现它正在使用call而不是callvirt你看看IL.C#编译器总是使用callvirt,即使对于非虚方法,因为它强制进行无效检查.

这是一个错误吗?嗯,不一定.它取决于F#语言规范对null引用的方法调用的说明.它完全有可能声明该方法将被调用(非虚拟),并带有一个空的"this"引用,这正是发生的事情.

C#碰巧指定这种解除引用会抛出一个NullReferenceException,但这是一种语言选择.

我怀疑F#方法可能会更快一些,因为缺乏无效性检查......并且不要忘记F#中的空引用不如C#中的"预期"......这可能解释了采用的不同方法这里.当然,它可能只是一种疏忽.

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

6.9.6评估方法应用

对于方法的详细应用,表达式的详细形式将是expr.M(args)或M(args).

  • (可选)expr和args按从左到右的顺序进行计算,成员的主体在具有映射到相应参数值的形式参数的环境中进行求值.

  • 如果expr求值为null,则引发NullReferenceException.

  • 如果该方法是虚拟调度槽(即,声明为abstract的方法),则根据expr值的调度映射选择成员的主体.

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