2016-04-23 46 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不受支持。所以我只是假设只限制类类型就行了。 –