Reputation: 3065
I am trying to write a spec utility library.
One of the Specification is a TExpressionSpecification. Basically, it implements the Specification pattern by evaluating an inner TExpression.
One of the TExpression is a TPropertyExpression. It's simply an expression that gets the value of a property by its name with Rtti.
I implemented it the simplest way I could, but really cannot understand why it throws an AV at me.
I stepped throrouly with the debugger. All types are what they are supposed to be. I just dont know why the TRttiProperty.GetValue is wrecking havoc.
Can anybody help? unit Spec;
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.
Upvotes: 1
Views: 1250
Reputation: 37211
GetValue
expects the instance pointer (aObject
) but you are passing it the address of the pointer variable (@aObject
).
Constrain your TObjectType
to a class type:
type
TPropertyExpression<TObjectType: class; TResultType> = class...
Then, instead of Addr(aObject)
, pass the instance directly:
aValue := aProperty.GetValue(Pointer(aObject));
Upvotes: 5