代码之家  ›  专栏  ›  技术社区  ›  Juraj Blahunka

从Delphi中的func/proc获取对象作为结果

  •  9
  • Juraj Blahunka  · 技术社区  · 15 年前

    最佳做法

    将创建的对象作为引用传递 ,在过程中填充对象,然后将其销毁

    procedure Proc(var Obj: TMyObject);
    begin
      // populate Obj
    end;
    
    O := TMyObject.Create;
    try
      Proc(O);
      // manipulate populated object
    finally
      O.Free;
    end;
    

    从函数中获取创建的对象作为结果 ,操纵后破坏

    function Func: TMyObj;
    begin
      Result := TMyObj.Create;
    end;
    
    O := Func;
    if O <> nil then
    begin
      try
        // manipulate
      finally
        O.Free;
      end;
    end;
    
    6 回复  |  直到 15 年前
        1
  •  8
  •   Rob Kennedy    15 年前

    没有最佳实践。 不过,您应该做的首要事情是确保在任何给定的时间都清楚谁负责销毁对象,即使在发生异常时也是如此。

    函数创建一个新实例并返回它没有错。这样的函数是一个函数 factory . 您可以像对待类的构造函数一样对待它,因此您应该确保它的行为类似于构造函数:要么返回有效对象,要么抛出异常。它从不返回空引用。

    function Func: TMyObj;
    begin
      Result := TMyObj.Create;
      try
        Result.X := Y;
      except
        Result.Free;
        raise;
      end;
    end;
    

    从函数到调用方,但前提是它能够完全执行。如果由于异常而必须提前离开,则会释放对象,因为调用方无法释放对象本身。(由于异常而终止的函数没有返回值。)调用者将这样使用它:

    O := Func;
    try
      writeln(O.X);
    finally
      O.Free;
    end;
    

    如果在中有异常 Func O 从不被分配,因此没有任何东西可供调用者使用。


    释放对象。调用方不会向其调用的函数授予所有权责任,特别是当它计划在函数返回后使用对象时。

        2
  •  4
  •   Mihaela    15 年前

    假设您的方法用解析文件的结果填充TStringList。 是让该函数创建TStringList,还是创建它并作为引用传递?

        3
  •  3
  •   jpfollenius Rob Kennedy    15 年前

    让调用者创建对象并将其作为参数传递是一种常见的Delphi习惯用法。请注意,您不必声明它 var 几乎在所有情况下。

    procedure Proc (Obj : TMyObject)
    begin
      Obj.SomeProperty := 'SomeValue';
      ...
    end;
    

    Obj := TMyObject.Create;
    try
      Proc (Obj);
    finally
      FreeAndNil (Obj);
    end;    
    

    这避免了关于谁必须释放对象的混淆。请注意,如果您有一系列方法调用,那么跟踪需要释放的对象很快就会变得非常复杂。

    try...finally

    如果您希望您的方法创建对象,我会在函数名中显式显示它,比如 CreateAndInitializeList 听起来不错。

        4
  •  2
  •   PA.    15 年前

    所以我的函数通常的签名是

    function Func(o:tMyO): TMyO;
    begin
      // ....
      Result := o;
    end;
    

       o := func(TMyO.create);
    

      o := TMyO.create;
      // ...
      func(o);
    
        5
  •  1
  •   Larry Lustig    15 年前

    但是,只有在调用者知道要返回的项的确切类型而不是超类型时,这才可能实现。例如:

    var E: TEmployee;
    
    E := CreateEmployee(EmployeeID);  // Could return TEmployee or subclasses TManager or TRetiredEmployee
    
    try
    
        E.SendEmail(MessageText);
        if (E is TRetiredEmployee) then
            E.PrintLetter;
    
    finally
    
        E.Free;
    
    end;
    

    在这种情况下,我发现在我调用的工厂函数的名称中包含单词“Create”或其他指示符是很有帮助的。

        6
  •  -3
  •   HeartWare    15 年前

    我经常使用这个结构

    FUNCTION SomeFunction(SL : TStrings = NIL) : TStrings;
      BEGIN
        IF Assigned(SL) THEN Result:=SL ELSE Result:=TStringList.Create;
        // Use Result for the remainder of the function
      END;
    

    这样,我既可以将其用作带有传入引用的过程,也可以将其用作创建实例本身的函数。

    推荐文章