2016-04-23 44 views
1

我想寫一個規範實用程序庫。Delphi Rtti獲取屬性 - 爲什麼這會導致AV?

規範之一是一個TExpressionSpecification。基本上,它通過評估內部TE表達來實現規範模式。

其中一個TExpression是TPropertyExpression。它只是一個表達式,它通過Rtti的名稱獲取屬性的值。

我以最簡單的方式實現了它,但真的無法理解它爲什麼會向我拋出AV。

我帶着調試器走了過去。所有類型都是他們應該是的。我只是不知道爲什麼TRttiProperty.GetValue破壞破壞。

任何人都可以幫忙嗎? 單位規格;

interface 

uses 

Classes; 

type 

TPropertyExpression<TObjectType, TResultType> = class 

private 
    FPropertyName: string; 
public 
    constructor Create(aPropertyName: string); reintroduce; 
    function Evaluate(aObject: TObjectType): TResultType; 
    property PropertyName: string read FPropertyName write FPropertyName; 
end; 

procedure TestIt; 

implementation 

uses 

Rtti; 

constructor TPropertyExpression<TObjectType, TResultType>.Create(aPropertyName: 
    string); 
begin 
    inherited Create; 
    PropertyName := aPropertyName; 
end; 

function TPropertyExpression<TObjectType, TResultType>.Evaluate(aObject: 
    TObjectType): TResultType; 
var 
    aCtx : TRttiContext; 
    aModelType : TRttiType; 
    aResultType : TRttiType; 
    aProperty : TRttiProperty; 
    aValue : TValue; 
begin 
    aCtx := TRttiContext.Create; 
    aModelType := aCtx.GetType(System.TypeInfo(TObjectType)); 
    aResultType := aCtx.GetType(System.TypeInfo(TResultType)); 
    aProperty := aModelType.GetProperty(PropertyName); 
    aValue := aProperty.GetValue(Addr(aObject)); 
    Result := aValue.AsType<TResultType>; 
end; 

procedure TestIt; 
var 
    aComponent : TComponent; 
    aSpec : TPropertyExpression<TComponent, string>; 
begin 
    aComponent := TComponent.Create(nil); 
    aComponent.Name := 'ABC'; 
    aSpec := TPropertyExpression<TComponent, string>.Create('Name'); 
    WriteLn(aSpec.Evaluate(aComponent)); 
    Readln; 
end; 

end. 

回答

5

GetValue預計實例指針(aObject),但你傳遞給它的指針變量(@aObject)的地址。

約束你TObjectType一類類型:

type 
    TPropertyExpression<TObjectType: class; TResultType> = class... 

然後,而不是Addr(aObject),通過直接實例:

aValue := aProperty.GetValue(Pointer(aObject)); 
+0

沒有必要強制類型轉換爲'Pointer',只是通過對象指針原來是:'GetValue(aObject)'。 –

+0

另外,請記住記錄也可以有屬性,所以你不應該使用'class'約束。除非你定義一個獨立的表達式類來獨立於類實例處理記錄實例。 –

+0

沒有演員,我得到E2010不兼容的類型:'指針'和'TObjectType'。雖然你說得對,記錄可以有屬性,但是記錄屬性的RTTI不受支持。所以我只是假設只限制類類型就行了。 –