Why can't Delphi variants hold objects? More importantly, what's the reason behind this limitation?
问题:
回答1:
This is just an opinion, from my experience with what variants can and cannot do.
If you put a COM object into it, it will be stored as an IDispatch reference, and thus any method calls or properties you access on this object will be converted into some code that looks up the internal DISPID of the method/property, an array with method arguments will be constructed, and the method will be invoked through the IDispatch interface.
In other words, IDispatch is handled for you, the way you would normally have to do it, but it's done automagically by the compiler.
However, for normal Delphi objects, things get harder. You can use RTTI to find, and call published methods and properties, but that's about it. If you have the name of a non-published, non-virtual method, Delphi can't find the right address for it on your method.
In other words, all you would be able to do would be to just hold the object, you wouldn't be able to use it. Perhaps they could add support for just freeing it, but again, that would probably be it.
I know for a fact that if you implement IDispatch correctly, you can safely store, and use the object through a variant. I have a class that can be used as the base class for Delphi objects you want to do this on. It will automatically expose published methods/properties, and you can add more if you want through some protected method calls. If there is an interest in such a class I can place it somewhere.
But again, this is through IDispatch, and it uses the published methods, the rest is manual code, so the support for variants have to be built into your objects, by you.
Which is why I think they just said: This will just generate complaints, that we can hold an object but it's just useless.
But that's just my thoughts. Perhaps someone official have a much better answer.
回答2:
You can definitely store an object inside a Variant variable - just cast it into a NativeUInt. An object is just a pointer, anyway.
obj := TObject.Create;
v := NativeUInt(obj);
obj := TSomeObject(NativeUInt(v));
回答3:
I had used Variants to hold objects in the past using the Variant internals, the code is something like this:
var
MyObject: TMyObject;
Value: Variant;
begin
MyObject:= TMyObject.Create;
TVarData(Value).VType:= VarByRef or VarUnknown;
TVarData(Value).VPointer:= MyObject;