0

TObjectDispatch の保護された仮想メソッドを拡張しようとしています。しかし、このメソッドは呼び出されません。

[問題を再現するために編集]。

GetPropInfo をオーバーライドして TMyDispatch で使用すると、期待どおりに動作します。オーバーライドされたメソッドが呼び出されます。ただし、TMyDispatch によって作成されたときに TMyDispatchItem のオーバーライドされたメソッド (実際の例をシミュレートするため) は呼び出されません。

{$METHODINFO ON}

  TExtDispatch = class(TObjectDispatch)
  protected
    function GetPropInfo(const AName: string; var AInstance: TObject;
      var CompIndex: Integer): PPropInfo; override;
  public
    constructor Create;
  end;

  TMyDispatchItem = class(TExtDispatch)
  private
    FItemValue: string;
  public
    procedure ShowItemValue;
  published
    property ItemValue: string read FItemValue write FItemValue;
  end;

  TMyDispatch = class(TExtDispatch)
  public
    function GetItem: TMyDispatchItem;
  private
    FValue: string;
  public
    procedure ShowValue;
  published
    property Value: string read FValue write FValue;
  end;

  {$METHODINFO OFF}

  TTestForm = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  TestForm: TTestForm;

implementation

{$R *.dfm}

procedure TTestForm.Button1Click(Sender: TObject);
var
  V: Variant;
  VI: Variant;
begin
  V := IDispatch(TMyDispatch.Create);
  V.Value := 100; //this calls inherited getpropinfo
  V.ShowValue;

  VI := V.GetItem;
  VI.ItemValue := 5; //this doesn't
  VI.ShowItemValue;
end;

{ TExtDispatch }

constructor TExtDispatch.Create;
begin
  inherited Create(Self, False);
end;

function TExtDispatch.GetPropInfo(const AName: string; var AInstance: TObject;
  var CompIndex: Integer): PPropInfo;
begin
  Result := inherited GetPropInfo(AName, AInstance, CompIndex);
  ShowMessage('GetPropInfo: ' + AName);
end;

{ TMyDispatch }

function TMyDispatch.GetItem: TMyDispatchItem;
begin
  Result := TMyDispatchItem.Create;
end;

procedure TMyDispatch.ShowValue;
begin
  ShowMessage('My dispatch: ' + Value);
end;

{ TMyDispatchItem }

procedure TMyDispatchItem.ShowItemValue;
begin
  ShowMessage('My item value: ' + FItemValue);
end;

end.

TMyDispatch.GetItemのデータ型を代わりにバリアントとして返すように変更することで、この問題を克服する方法を実際に見つけました。このような:

function TMyDispatch.GetItem: Variant;
begin
   Result := IDispatch(TMyDispatchItem.Create);
end;

そして今、突然オーバーライドされたメソッドが呼び出されます。ここで何が起こっているのかを本当に理解したいと思います。

これ以上のアイデアや説明はありますか?

4

1 に答える 1

3

Delphi の仮想メソッド ディスパッチは動作することが知られています。したがって、TExtDispatch.GetPropInfoが実行されていない場合は、次の理由が考えられます。

  1. GetPropInfoメソッドはまったく呼び出されていません。
  2. GetPropInfoが呼び出されている実際のインスタンスはのインスタンスではありませんTExtDispatch

コードの残りの部分を示していただければ、より確信が持てますが、上記のオプションで十分に解決できるはずです。

呼び出す場所は だけGetPropInfoですGetIDsOfNames。オーバーライドされたものが呼び出されない場合、他に何もGetIDsOfNames呼び出されません。GetPropInfo


更新されたコードを考慮して、デバッガーで実行しました。ボタンがクリックされると、TObjectDispatch.GetPropInfoが 2 回呼び出されます。inherited GetPropInfo()in の呼び出しの結果として初めて呼び出されたときTExtDispatch.GetPropInfo。2回目に呼び出されたときに、検査ClassNameしてクラスSelfが何であるかを調べることができます。ClassNameこれを行うと、 が に評価されることがわかります'TObjectDispatch'。その場合、私のリストの項目 2 が説明です。


あなたがここで何をしようとしているのか、私にはよくわかりません。GetItemただし、問題は実装方法に起因すると思われます。私はそれが次のようであるべきだと思う:

function TMyDispatch.GetItem: IDispatch;
begin
  Result := TMyDispatchItem.Create;
end;

TInterfacedObjectコンストラクターの戻り値をオブジェクト参照に割り当てたときに、警鐘が鳴るはずでした。それは常にエラーです。それをインターフェイス参照に割り当てる必要があります。

何が起こるかというと、ディスパッチ コードは、見つかった場合は を使用IDispatchしますが、クラスのインスタンスが見つかった場合は、代わりに newIDispatchを作成して作業を行うことを期待しています。これが の 3 番目のインスタンスですTObjectDispatch

于 2013-03-06T14:17:13.873 に答える