tags:

views:

492

answers:

2

Hey all, first sorry for my bad english. Consider the following (not actual code):

IMyInterface = Interface(IInterfce)
  procedure Go();
end;

MyClass = class(IMyInterface)
  procedure Go();
end;

MyOtherClass = class
published
  property name: string;
  property data: MyClass;
end;

I'm setting "MyOtherClass" properties using RTTI. For the string property it's easy, but my question is:

How can I get a reference to the "data" (MyClass) property so I can call the Go() method?

I want to do something like this (pseudo-code):

for i:= 0 to class.Properties.Count  
  if (propertyType is IMyInterface) then
    IMyInterface(class.properties[i]).Go()

(if only this was C# :( )

PS.: this is in delphi 7 (i know, even worse)

+1  A: 

You can get an array of all published propertied by calling GetPropInfos(MyClass.ClassInfo). This is an array of PPropInfo pointers. And you can get at type-specific data from a PPropInfo by calling GetTypeData on it, which returns a PTypeData. The record it points to will have the information you're looking for about the class reference.

Mason Wheeler
+2  A: 

If the string property is easy, as you say, then I assume you're calling GetStrProp and SetStrProp from the TypInfo unit. Class-type properties can be equally easy with GetObjectProp and SetObjectProp.

if Supports(GetObjectProp(Obj, 'data'), IMyInterface, Intf) then
  Intf.Go;

If you don't really need the interface, and you know that the data property has type TMyClass, then you can go a little more directly:

(GetObjectProp(Obj, 'data') as TMyClass).Go;

That requires the property to have a non-null value.

If you don't know the name of the property you want, then you can use some other things in TypInfo to search for it. For example, here is a function that will find all the published properties of an object that have values that implement IMyInterface; it calls Go on each of them in no particular order.

procedure GoAllProperties(Other: TObject);
var
  Properties: PPropList;
  nProperties: Integer;
  Info: PPropInfo;
  Obj: TObject;
  Intf: IMyInterface;
  Unk: IUnknown;
begin
  // Get a list of all the object's published properties
  nProperties := GetPropList(Other.ClassInfo, Properties);
  if nProperties > 0 then try
    // Optional: sort the list
    SortPropList(Properties, nProperties);

    for i := 0 to Pred(nProperties) do begin
      Info := Properties^[i];
      // Skip write-only properties
      if not Assigned(Info.GetProc) then
        continue;

      // Check what type the property holds
      case Info.PropType^^.Kind of
        tkClass: begin
          // Get the object reference from the property
          Obj := GetObjectProp(Other, Info);
          // Check whether it implements IMyInterface
          if Supports(Obj, IMyInterface, Intf) then
            Intf.Go;
        end;

        tkInterface: begin
          // Get the interface reference from the property
          Unk := GetInterfaceProp(Obj, Info);
          // Check whether it implements IMyInterface
          if Supports(Unk, IMyInterface, Intf) then
            Intf.Go;
        end;
      end;
    end;
  finally
    FreeMem(Properties);
  end;
end;
Rob Kennedy
Thank you Rob, your solution perfectly solved my problem. That was exactly what i was looking for - You deserve the RTTI-Hero badge :)
Leo