Ludovic C
Ludovic C

Reputation: 3065

Delphi Rtti Get Property - Why does this results in AV?

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

Answers (1)

Ondrej Kelle
Ondrej Kelle

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

Related Questions