Creating Delphi Objects at runtime based on class type
Is it possible to create objects at runtime based on it's type by calling a method.
开发者_开发问答What I am trying to achieve is
var
lForm1 : TForm;
lForm2 : TForm;
begin
CreateObjects([lForm1, lForm2]);
// After this call I have the variables initialized and I can use them.
end;
There is insufficient information in the question.
Where does the "type" of the form objects (in the question) come from? Is it simply a type name? How does CreateObjects() discover the type that is required for each object?
It cannot come from the "type" of the object reference passed in, as this may be (and almost certainly will be, as in your example) merely a base type from which the required concrete type will ultimately derive.
Without more detailed information about your specific implementation goals and constraints, a complete, concrete answer is not possible.
However, in general terms what you seek may be achieved by a combination of virtual constructors and the RegisterClass / FindClass infrastructure provided by the VCL.
In simple terms, you would have a base class that introduces the common constructor used to instantiate your classes [for TComponent derived classes this already exists in the form of the Create(Owner: TComponent) constructor].
At runtime you can then obtain a reference to any (registered) class using FindClass('TClassName'). This will return a class reference with which you can then invoke the appropriate virtual constructor:
type
TFoo = class ....
TFooClass = class of TFoo;
// etc
var
someClass: TFooClass;
someObj: TFoo;
begin
someClass := TFooClass(FindClass('TFooDerivedClass'));
someObj := someClass.Create(nil);
:
Note in the above that TFooDerivedClass is a class that ultimately derives from TFooClass (and is assumed for simplicity to derive in turn from TComponent and is instantiated with a NIL owner in this case). Classes that are already registered with the type system can be found using FindClass(). This includes any control or component class that is referenced by some DFM in your application. Any additional classes that need to be registered may be explicitly registered using RegisterClass().
How your specific application identifies the types of objects involved and any mapping of type names onto other arbitrary system of identification is an implementation detail that you must take care of.
Untested concept code:
function instantiate(var instancevars : array of tobject;
const classtypes : array of TBaseClassType):boolean;
begin
if (length(instancevars)=0) or (length(instancevars)<>length(classtypes)) then
exit(false);
for i:=0 to length(instancevars)-1 do
instancevars[i]:=classtypes[i].create;
result:=true;
end;
Then use
instantiate([lform1,lform2],[tform1,tform2]);
to make it work.
Note for this to work "TBaseClassType" must be some baseclass for all classes used for this function, and have a virtual constructor (e.g. TPersistent?). Possibly you also need to correct the .create line (e.g. add (NIL) )
You can't get a type from a variable, the information is only available compiletime.
Quoting your comment on Henk's answer :
That's what I don't want to do. I have a lot of server side methods where I create a lot of controls at runtime and I was wondering is creating objects as above would reduce the code.
What do you mean by "a lot"?
If you mean a lot of components of exactly the same type (e.g : "but1, but2, but3, .. but55 : TButton;" ) then change your code and use an array to represent your variables - you can then make a simple loop to create them.
If you mean a lot of components of different types (e.g : but1 : TAnimatedButton; but2 : TFlatButton; but3 : T3DButton;), I don't see any simple method to do this, and I think you would create a small debugging hell more than anything else.
精彩评论