2017-03-16 5 views
2

RTTI를 사용하여 복잡한 구조의 클래스를 반복해야합니다. 이 클래스에는 반복하려는 여러 레코드 멤버가 있습니다.Delphi - 일반 TValue 전달

for prop in rt.GetProperties() do 
    begin 
     if prop.PropertyType is TRttiRecordType then 
     begin 
     lValue := prop.GetValue(aInst); 
     Result.AddStrings(TRTTIHelpers<T>.DoGetValuesForRecord(TValue)); <-- 
     end 

가 어떻게 그렇게 나는 또한 기록을 반복 할 수 DoGetValuesForRecord에 대한 매개 변수로 TValue을 전달할 수 있습니다 : 나는 기록이다 클래스의 구성원이있을 때 내가 아는

TRTTIHelpers<T> = class 
    public 
    class function DoGetValuesForClass(aClassInst: T): TStringList; 
    class function DoGetValuesForRecord(aRec: T): TStringList; 
    end; 

?

답변

7

T에 값을 캐스팅 TValueAsType<T> 방법을 사용

물론
{$APPTYPE CONSOLE} 

uses 
    System.RTTI; 

type 
    TMyRecord = record 
    foo: Integer; 
    end; 

    TMyClass = class 
    function GetRec: TMyRecord; 
    property Rec: TMyRecord read GetRec; 
    function GetInt: Integer; 
    property Int: Integer read GetInt; 
    end; 

function TMyClass.GetRec: TMyRecord; 
begin 
    Result.foo := 42; 
end; 

function TMyClass.GetInt: Integer; 
begin 
    Result := 666; 
end; 

procedure Main; 
var 
    inst: TMyClass; 
    ctx: TRttiContext; 
    typ: TRttiType; 
    prop: TRttiProperty; 
    value: TValue; 
    rec: TMyRecord; 
begin 
    inst := TMyClass.Create; 
    typ := ctx.GetType(TypeInfo(TMyClass)); 
    for prop in typ.GetProperties do begin 
    if prop.Name='Rec' then begin 
     value := prop.GetValue(inst); 
     rec := value.AsType<TMyRecord>; 
     Writeln(rec.foo); 
    end; 
    end; 
end; 

begin 
    try 
    Main; 
    except 
    on E: Exception do 
     Writeln(E.ClassName, ': ', E.Message); 
    end; 
    Readln; 
end. 

,이 재산 prop가이다 것을 요구 않습니다

lValue := prop.GetValue(aInst); 
Result.AddStrings(TRTTIHelpers<T>.DoGetValuesForRecord(lValue.AsType<T>)); 

이 간단한 프로그램이 보여 올바른 유형. 그렇지 않으면 런타임 오류가 발생합니다. 위의 예에서 속성의 이름을 테스트하여 원하는 속성을 얻을 수 있는지 확인합니다. 해당 테스트를 제거하면 런타임에 EInvalidCast 오류로 프로그램이 실패합니다.

코드를 보면 나는 이러한 오류가 발생할 가능성이 높다고 생각합니다. rt의 모든 속성이 동일한 유형 인 경우 나에게 놀라운 것입니다.

TRTTIHelpers<T>에서 보니 매우 유용 할 것 같지 않습니다. 적어도 RTTI 기반의 코드와는 잘 상호 작용하지 않을 것입니다. TRTTIHelpers<T>을 호출하는 이유는 컴파일 타임에 type 매개 변수를 제공해야하기 때문입니다. 그러나 RTTI 코드를 사용하면 컴파일 타임에 해당 유형을 알 수 없습니다. 나는 아마도 TRTTIHelpers<T>이 제네릭 클래스가 아니어야하고 대신 RTTI 유형을 사용하여 런타임에 결정된 유형의 입력에 대해 융통성있는 기능을 제공한다고 생각합니다. 이 충고는 당연히 잘못 될 수 있지만, 나는 가이드의 질문에 단지 작은 발췌문 만 가지고있다.

+0

글쎄, 당신이 물어 본 질문에 대한 답변입니다. 런타임 오류는'lValue'에있는 것이 모두'T' 유형이 아니라는 것을 알려줍니다. –

+0

lValue에있는 내용은 TRTTIRecordType 유형입니다. prop.PropertyType이 TRttiRecordType 인 경우 - 내 클래스에 레코드 유형이 있습니다 – RBA

+0

예, 레코드 유형입니다. 하지만 실행 시간 오류가 알려주므로 반드시 일반 'T'와 동일한 유형 일 필요는 없습니다. –