2010-06-10 4 views
1

저는 최근에 인터페이스와 D2010 RTTI를 광범위하게 실험했습니다. 런타임시 인터페이스의 실제 유형을 알지 못합니다. 문자열을 사용하는 정규화 된 이름에 액세스 할 수는 있지만 다음 mynamespace.pasTValue를 사용하여 델파이 인터페이스 캐스트

program rtti_sb_1; 
{$APPTYPE CONSOLE} 
uses 
    SysUtils, Rtti, TypInfo, mynamespace in 'mynamespace.pas'; 
var 
    ctx:     TRttiContext; 
    InterfaceType:  TRttiType; 
    Method:    TRttiMethod; 
    ActualParentInstance: IParent; 
    ChildInterfaceValue: TValue; 
    ParentInterfaceValue: TValue; 
begin 
    ctx := TRttiContext.Create; 
    // Instantiation 
    ActualParentInstance := TChild.Create as IParent; 
    {$define WORKAROUND} 
    {$ifdef WORKAROUND} 
    InterfaceType := ctx.GetType(TypeInfo(IParent)); 
    InterfaceType := ctx.GetType(TypeInfo(IChild)); 
    {$endif} 
    // Fetch interface type 
    InterfaceType := ctx.FindType('mynamespace.IParent'); 
    // This cast is OK and ChildMethod is executed 
    (ActualParentInstance as IChild).ChildMethod(100); 
    // Create a TValue holding the interface 
    TValue.Make(@ActualParentInstance, InterfaceType.Handle, ParentInterfaceValue); 
    InterfaceType := ctx.FindType('mynamespace.IChild'); 
    // This cast doesn't work 
    if ParentInterfaceValue.TryCast(InterfaceType.Handle, ChildInterfaceValue) then begin 
    Method := InterfaceType.GetMethod('ChildMethod'); 
    if (Method <> nil) then begin 
     Method.Invoke(ChildInterfaceValue, [100]); 
    end; 
    end; 
    ReadLn; 
end. 

내용된다 :

다음을 고려해야

procedure TParent.ParentMethod(const Id: integer); 
begin 
    WriteLn('ParentMethod executed. Id is ' + IntToStr(Id)); 
end; 
procedure TChild.ChildMethod(const Id: integer); 
begin 
    WriteLn('ChildMethod executed. Id is ' + IntToStr(Id)); 
end; 

{$define WORKAROUND} 이유가있을 수 있으므로

완전성
{$M+} 
IParent = interface 
    ['{2375F59E-D432-4D7D-8D62-768F4225FFD1}'] 
    procedure ParentMethod(const Id: integer); 
end; 
{$M-} 
IChild = interface(IParent) 
    ['{6F89487E-5BB7-42FC-A760-38DA2329E0C5}'] 
    procedure ChildMethod(const Id: integer); 
end; 
TParent = class(TInterfacedObject, IParent) 
public 
    procedure ParentMethod(const Id: integer); 
end; 
TChild = class(TParent, IChild) 
public 
    procedure ChildMethod(const Id: integer); 
end; 

, 구현 간다 발견 된 in this post.

질문 : RTTI를 사용하여 원하는 유형의 캐스트를 만들 수있는 방법이 있습니까? 즉, IChild.ChildMethod를 호출하여 IChild의 정규화 된 이름을 문자열로, 2) Tarent 인스턴스를 IParent 인터페이스로 참조하는 것을 알 수있는 방법이 있습니까? (결국, 하드 코딩 된 캐스트가 잘 작동합니다.이게 가능합니까?) 감사합니다!

답변

2

이것은 RTTI.pas에서 꽤 느린 코딩의 추악한 사례처럼 보입니다. TValue 내에서 인터페이스 캐스트를 처리하는 ConvIntf2Intf 함수에서 명시 적으로 확인 만하면 IInterface으로 전송되는지 확인합니다. 다른 인터페이스는 자동으로 false를 반환합니다. 쉽게 GUID (인터페이스가있는 경우)를 추출하고 QueryInterface 호출을 시도 할 수 있지만 어떤 이유로 든 수행하지는 않습니다. 나는 이것을 QC에보고 할 것입니다.

+0

남자, 그렇게 많은 의미가 있습니다! 왜 이것이 작동하지 않는지 나는 정말로 이해할 수 없었다. 다시 한 번 구조하십시오! :) (+1) 아침에 QC에보고하겠습니다. – conciliator

+0

오전이 예상보다 빨리 나타났습니다. 이제 QC# 85339에서 신고되었습니다. – conciliator