views:

372

answers:

2

I've got two questions (of which at least one is regarding RTTI in D2010 and dynamic instancing)

  1. I was reading what appears to be the foils for a conference talk by Barry Kelly, and found on p. 13 something that looked really interesting: TRTTIConstructor.Invoke. In an adjacent bullet point, one finds "Dynamically construct instances without needing virtual constructors and metaclasses". This seems like a great feature (and exactly what I need, btw)! However, when I look in the D2010 docs (ms-help://embarcadero.rs2010/vcl/Rtti.html), I can't find it. Did it get revoked?
  2. What is the minimal way of creating an instance of a class, provided the class name is stored in a string?
+9  A: 

I think that functionality has been absorbed into TRttiMethod. It has IsConstructor, IsDestructor and IsClassMethod properties so that it can be used for "special" types of methods as well as normal ones.

As for question 2, try something like this:

function GetConstructor(val: TRttiInstanceType): TRttiMethod;
var
   method: TRttiMethod;
begin
   for method in val.GetMethods('Create') do
   begin
      if (method.IsConstructor) and (length(method.GetParameters) = 0) then
         exit(method);
   end;
   raise EInsufficientRTTI.CreateFmt('No simple constructor available for class %s ',
                                     [val.MetaclassType.ClassName]);
end;

This finds the highest constructor called Create that takes no parameters. You can modify it to look for other constructors with other signatures, if you know what you're looking for. Then just call Invoke on the result.

Mason Wheeler
Thanks again Mason! You (and the other folks here at SO) pretty much close the documentation gap. Thank you so much. + 1
conciliator
Glad to help. I was at that talk, and D2010 was still in beta at the time. It looks like a few things have changed from then to the final version. I wonder why HasAttribute got removed. That would be very useful!
Mason Wheeler
+2  A: 

Although you can call .GetMethod() to get the constructor you can also do the following to construct instances of objects with no parameters for the constructor.

function CreateInstance(aType : TRttiType) : TObject;
begin
  // Option #1
  result := aType.AsInstance.MetaclassType.Create;
  // Option #2
  result := aType.GetMethod('Create').Invoke(aType.AsInstance.MetaclassType,[]);
end;

If know the base type you can type cast the class to pass the parameters if you wish. Here is an example of creating a Component

result := TComponentClass(aType.AsInstance.MetaClassType).Create(OwnerValue);

Robert Love
Thanks Robert! For my current project I know the base type beforehand, so the last line in your answer would be just what the doctor ordered. (+1) However, I do get an access violation when I run Button := TButton(RType.ClassType).Create(self); where Button: TButton and self is the owner form, and RType: TRTTIType created by RType := RContext.FindType('StdCtrls.TButton'); (and the context is already created). What am I doing wrong?
conciliator
Try this:Button := TComponentClass(RType.AsInstance.MetaclassType).Create(Self) as TButton;
Ville Krumlinde
Thanks, VilleK. Alas, I still get an access violation. I'm guessing I should make a separate post regarding this.
conciliator
Maybe RContext.FindType('StdCtrls.TButton') returns nil? If so add a button to a form in your project to make TButton-rtti be included in the executable.
Ville Krumlinde
Well, I was considering that but run-time inspection says otherwise. Anyway, I already had an existing button on the form. It's not on the top of my list right now anyway, since the classes I need to create dynamically are some custom classes I wrote (which gets created just fine). Some day not long from now, however, I'll need to create a TButton on the fly, so I'll definitely have to look into it.
conciliator