Delphi 为什么没有引发NullReferenceException?

Delphi 为什么没有引发NullReferenceException?,delphi,delphi-xe2,Delphi,Delphi Xe2,我已经向几位同事展示了这一点,但没有人对此做出解释。 我偶然发现了这一点,因为我认为我在代码中发现了一个bug,但惊讶地发现代码实际上运行了。 这是一个简化的版本。 这是用XE-2完成的 到目前为止,我与之交谈过的每个人都希望抛出NullReferenceException TUnexplainable = class(TObject) public function Returns19: Integer; end; function TUnexplainable.Retur

我已经向几位同事展示了这一点,但没有人对此做出解释。 我偶然发现了这一点,因为我认为我在代码中发现了一个bug,但惊讶地发现代码实际上运行了。 这是一个简化的版本。 这是用XE-2完成的

到目前为止,我与之交谈过的每个人都希望抛出NullReferenceException

 TUnexplainable = class(TObject)
  public
    function Returns19: Integer;
  end;

function TUnexplainable.Returns19: Integer;
begin
  Result := 19;
end;
下面的测试永远不会工作,但它会成功运行。为什么没有引发NullReferenceException

procedure TTestCNCStep.ShouldNeverEverWorkV4;
var
  Impossible: TUnexplainable;
  Int1: Integer;
begin
  Impossible := nil;
  Int1 := Impossible.Returns19; // A Null Reference Exception should ocurr here!!! Instead the method Returns19 is actually invoked!!!!
  Check(Int1 = 19);
end;

您的方法从不引用
Self
指针,因此它正好工作


与C#不同,Delphi不会自动验证C#中的
Self
)指针。

非静态类方法编译为带有隐藏
Self
参数的独立函数。因此,从编译器的角度来看,您的代码基本上执行以下操作:

//function TUnexplainable.Returns19: Integer;
function TUnexplainable_Returns19(Self: TUnexplainable): Integer;
begin
  Result := 19;
end;

//procedure TTestCNCStep.ShouldNeverEverWorkV4;
procedure TTestCNCStep_ShouldNeverEverWorkV4(Self: TTestCNCStep);
var
  Impossible: TUnexplainable;
  Int1: Integer;
begin
  Impossible := nil;
  Int1 := TUnexplainable_Returns19(Impossible);
  Check(Int1 = 19);
end;
正如您所看到的,
Returns19()
没有引用任何东西的
Self
,因此没有理由发生零指针错误

更改代码以使用
Self
,然后您将看到预期的错误:

type
  TUnexplainable = class(TObject)
  public
    Number: Integer;
    function ReturnsNumber: Integer;
  end;

function TUnexplainable.ReturnsNumber: Integer;
begin
  Result := Number;
end;

procedure TTestCNCStep.ShouldNeverEverWorkV4;
var
  Impossible: TUnexplainable;
  Int1: Integer;
begin
  Impossible := nil;
  Int1 := Impossible.ReturnsNumber; // An EAccessViolation exception will now occur here!!!
end;
我已经向几位同事展示了这一点,但没有人对此做出解释


我会非常担心与一群同事(假设他们是程序员)一起工作,他们不了解类方法和
Self
参数的实际工作原理,也不了解通过nil指针调用类方法如何避免空指针错误。这类似于面向对象编程101之类的东西。

代码不引用堆上的任何对象字段,因此无需使用自引用。另请参阅,谢谢我现在理解了。来自C++和C i,我确信这会导致异常。我在使用Delphi时遇到的一个困难是,我没有发现涉及该语言的最新书籍。所以,即使你想深入了解德尔菲,几乎没有任何新的资料可用。我所描述的是C++如何工作。然而,C#是不同的,因为.NET是一个托管环境,它检查对象指针和方法调用的有效性。@santiagoIT-这里涉及的行为对于Delphi来说并不新鲜。它是Delphi自1.0版以来生成的运行时代码行为的基本部分。e、 TObject上的“Free”方法显式地依赖于使用NIL对象引用调用方法的能力。简单地说,优秀的Delphi对于这类事情仍然是高度相关和有用的。另外值得注意的是,这种行为仅限于非虚拟方法。使用声明为虚拟的Returns19尝试完全相同的操作,并使用NIL对象引用调用该操作将导致异常。@Deltics:“此行为仅限于非虚拟方法”-非常正确。调用
virtual
dynamic
方法需要访问对象的vtable/dispatch表,该表只能通过有效的对象指针访问。