TDataModule的子类没有使用.Create方法而被“创建”,但没有任何问题?

7

我突然注意到我们的代码库中有一个TDataModuleTestExchange(nil) '构造函数调用':

procedure TDialoogConfigExchange.ButtonTestClick(Sender: TObject);
var
   lDataModuleTestExchange: TDataModuleTestExchange;
   lResult                : Boolean;
begin
   inherited;
   [snip]
   begin
      lDataModuleTestExchange := TDataModuleTestExchange(nil);  // *** HERE ***
      try
         lResult := lDataModuleTestExchange.GetCalendarFolder(EditHost.Text,EditGebruiker.Text,EditWachtwoord.Text);
         if lResult then
            ToonMelding(sExchangeTestGelukt, mtInformation, [mbOk])
         else
            ToonMelding(Meldingen.Text, mtError, [mbOK]);
      finally
         lDataModuleTestExchange.Free;
      end;
   end;
end;

所以,不要使用TDataModuleTestExchange.**Create**(nil),使用以下代码即可:

unit dmTestExchange;

interface

uses
  System.SysUtils, System.Classes,
  Xml.XMLDoc, Xml.XMLIntf, Xml.XMLDOM,
  TimeTellDM;

type
  TDataModuleTestExchange = class(TTimeTellDataModule)  // TDataModule descendant
  private
  public
    function GetCalendarFolder(const AExchangeServerURL,AExchangeLoginName,AExchangePass: String): Boolean;
  end;

没有编译错误,也没有运行时问题。为什么呢?

2
TButton(nil).Dragging 也是安全的 ;) - kobik
2
@kobik 所以,当没有控件被拖动时,TButton(nil).DraggingTrue - David Heffernan
1个回答

5
首先,值得指出的是,该语句中的 cast 是伪造的,除了混淆之外没有任何作用。该代码等价于:
lDataModuleTestExchange := nil;

TDataModuleTestExchange.GetCalendarFolder是一个实例方法,你正在调用一个nil引用。如果该方法尝试访问任何实例中的字段、调用虚拟方法或依赖实例的任何内容,则会导致运行时错误。因此,似乎TDataModuleTestExchange.GetCalendarFolder的实现不依赖于实例。虽然您似乎在这里得逞了,但编写这样的代码显然非常糟糕。

该类可能需要重新编写为声明静态类方法,如下所示:

type
  TDataModuleTestExchange = class(TTimeTellDataModule)  
  public
    class function GetCalendarFolder(const AExchangeServerURL,  
      AExchangeLoginName, AExchangePass: string): Boolean; static;
  end;

然后像这样调用:

lResult := TDataModuleTestExchange.GetCalendarFolder(EditHost.Text,
  EditGebruiker.Text, EditWachtwoord.Text);
if lResult then
  ToonMelding(sExchangeTestGelukt, mtInformation, [mbOk])
else
  ToonMelding(Meldingen.Text, mtError, [mbOK]);

谢谢,这只是一个简单的打字错误。它并不是一个类方法,我已经添加了 .Create。 实际上,函数 GetCalendarFolder 没有访问私有变量,也没有调用虚拟方法:因为我的代码显示 TDataModuleTestExchange 没有,TTimeTellDataModule = class(TDataModule) 也没有。 - Jan Doggen
这不是真的。TDataModuleTestExchange 继承自 TDataModule,它既有数据字段又有虚方法。你真的应该将其作为类方法,因为它不使用任何实例数据,因此启动一个实例什么也不做是浪费和误导的。在我看来。 - David Heffernan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接