我有这个 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 TestCSProject
printfn "%d" (TestClass.Instance.Add(10,20))
没有人启动Instance
静态变量。猜猜 F# 应用程序的输出是什么?
this is null 30 Press any key to continue . . .
经过几次测试我发现除非我使用 this
(例如访问实例字段),否则我不会得到 NullReferenceExpcetion。
这是 F# 编译/CLR 中的预期行为还是漏洞?
最佳答案
如果您查看 IL,我怀疑您会发现它使用的是 call
而不是 callvirt
。 C# 编译器始终使用 callvirt
,即使对于非虚拟方法也是如此,因为它会强制执行无效检查。
这是一个错误吗?好吧,不一定。这取决于 F# 语言规范对空引用的方法调用的规定。它完全有可能声明将使用空“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.
这是否算作一个精心设计的应用程序我有点不知所措,恐怕......但我希望这至少能有所帮助。
关于c# - F#/.NET 空实例异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3752841/