【问题标题】:Class Helper and Class Interceptor in Delphi XE2Delphi XE2 中的类助手和类拦截器
【发布时间】:2012-12-10 17:49:24
【问题描述】:

我有一段代码如下所示:

接口部分:

TControlOrganizer = class(TComponent)  // a kind of List of TControl
private
  FList : TList;  //Handling list of TControl
  ..............
end;

TControlHelperAdd = class // Just for separating value entered by user and value produced by code
  private
    FOrganizer : TControlOrganizer;
    FOrigValue : String;
    FUserValue : String;
end;

TControlHelper = class helper for TControl  //Basic helper for TControl
  private
    class var
      FAddProp : TControlHelperAdd;
  protected
    procedure SetOrganizer(Value : TControlOrganizer);
    function getOrganizer:TControlOrganizer;
  public
    class Constructor doinit;
    class Destructor deinit;
    procedure OrganizerChanged;virtual;
  published
    Property Organizer:TControlOrganizer read getOrganizer write setOrganizer; //Problem No.1
  end;

//Helper for CustomEdit inherited from TControlHelper
TCustomEditHelper = class helper(TControlHelper) for TCustomEdit
  protected
    procedure OrganizerChanged;override;
  end;
//TEdit : interceptor
TEdit= class(StdCtrls.TEdit)
  protected
    procedure Change;override;  //problem No.3
end;

实现部分:

{TControlHelper}

class Constructor TControlHelper.doinit;
begin
  FAddProp :=TControlHelperAdd.Create;
end;

class Destructor TControlHelper.deinit;
begin
  FreeAndNil(FAddProp);
end;

procedure TControlHelper.OrganizerChanged;
begin
end;

procedure TControlHelper.SetOrganizer(Value : TControlOrganizer);
begin
  if FAddProp.FOrganizer<>value then begin
     if assigned(FAddProp.FOrganizer) then begin
       FAddProp.FOrganizer.remove(self);
     end;
     FAddProp.FOrganizer:=value;
     if assigned(FAddProp.FOrganizer) then begin
       FAddProp.FOrganizer.Add(self);
     end;
     OrganizerChanged;  //Problem No.2
  end;
end;

function TControlHelper.getOrganizer:TControlOrganizer;
begin
  result:=FAddProp.FOrganizer;
end;

{TCustomEditHelper}
procedure TCustomEditHelper.OrganizerChanged; //problem No.2
begin
  if assigned(FAddProp) then begin
    if assigned(Organizer) then begin
      FAddProp.FOrigValue:=Text;
      FAddProp.FUserValue:=Text;
    end;
  end;
end;

{TEdit = Interceptor} 
procedure TEdit.Change; //Problem No.3
begin
  inherited Change;
  FAddProp.FUserValue:=Text;
end;

我发现了 3 个我自己无法解决的问题。

问题 1: 已发布的属性属性未显示在对象检查器中。我想我犯了一个错误,在这里忘记了一些东西。

问题 2: 如上所示,来自类助手的重写方法没有触发(没有工作)。

问题 3: 如上所示,拦截器类中的重写方法没有触发(不起作用)。

谁能帮我找出问题所在? 感谢您的帮助,并为我糟糕的英语感到抱歉。

【问题讨论】:

  • 抱歉不太清楚。问题 1:已发布的属性没有出现在检查员身上。问题2:这是否意味着助手不允许继承,尤其是覆盖方法?问题 3:这是否意味着我更喜欢创建从 TEdit 派生的新类而不是实例化拦截器?
  • 您知道吗,FAddProp 对于所有相关实例都是全局唯一的,而不是每个实例唯一的,因为它是一个类字段?在这个用例中似乎没用
  • 谢谢。你说的对。 FAddProp 是一个全局单位。我发现一些文档来自 delphi.about.com,以便更好地使用拦截器而不是帮助器。
  • 在使用拦截器之前,我会考虑适配器,因为副作用较少

标签: delphi delphi-xe2


【解决方案1】:

问题 1

帮助器中的已发布属性不会显示在对象检查器中。

没错。在帮助器中声明的属性永远不会出现在对象检查器中。

问题 2

虚拟方法在类助手中无效。

同样,这是设计使然。尽管编译器允许您在帮助程序中定义虚拟方法,但它没有任何作用。为了让TCustomEditHelper.OrganizerChanged 触发,TCustomEditHelper 需要成为目标对象的主动助手。

问题 3

我截获的TEdit 类的Change 方法没有触发。

那是因为你没有实例化截获的TEdit。如果您实例化正确的类,即您定义的拦截器类,该方法将触发。

【讨论】:

  • 问题 3 只需将拦截器单元名称放在“uses”中的 stdctrls 之后即可。问题1和2通过使用继承类解决。 helper 类只是为了帮助添加一些简单的方法。
  • @David Heffernan 如果我们将帮助程序类注册为使用 registercomponents ,帮助程序的已发布属性不会出现在对象检查器中吗?有没有办法让属性出现在oi中?
【解决方案2】:

帮助类可以被认为是一个常规的非面向对象的函数,它接受对象作为它的第一个参数。助手让您可以隐藏它并像调用方法一样编写代码。如果您将它们视为简单的函数,那么您就会明白为什么它们不会出现在对象检查器中或使用访问对象内部的任何地方(如虚拟方法表、调度方法和发布的属性),因为没有内部对象的变化。

【讨论】:

    【解决方案3】:

    这样的决定不言自明。

    TControlHelper = class helper for TControl
    private
        function GetTest: Integer;
    protected
        property Test: Integer read GetTest;
    end;
    
    TMyThing = class(TControl)
    published
        property Test;
    end;
    

    您将看到“设计时测试”属性。 然而,在编译一个真实的项目时,我们得到 [dcc32 致命错误] F2084 内部错误:AV0A967995(0A8F0000)-R00000000-0

    【讨论】:

    • 但是,我找到了解决方案。 TControlHelper = TControl 保护函数 GetTest 的类助手:整数;结尾; TMyThing = class(TControl) 发布属性 Test: Integer read GetTest;结尾; Integer 类型在这里是有条件的,它可能是您需要的类,TControlHelper 将从例如 Spring.Services.ServiceLocator 通过在第一次调用时创建它来剪切给您的实例。关键是 Self
    • 请不要添加 cmets 来澄清。 cmets 中的代码不可读。 Edit 你的答案。
    【解决方案4】:

    不过,我找到了解决办法。

    TControlHelper = class helper for TControl
    protected
    function GetTest: Integer;
    end;
    
    TMyThing = class (TControl)
    published
    property Test: Integer read GetTest;
    end;
    

    这里的Integer类型是有条件的,可能是你需要的类, TControlHelper 将从中切入的一个实例,例如, Spring.Services.ServiceLocator 在第一次通话时创建它。关键是 Self

    【讨论】:

      猜你喜欢
      • 2020-01-19
      • 2011-11-20
      • 1970-01-01
      • 2013-06-19
      • 1970-01-01
      • 2012-10-22
      • 2012-06-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多