Why can't Delphi variants hold objects? More importantly, what's the reason behind this limitation?
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.
IInterface
AKA IUnknown
into the variant. Then yuo can use Delphi standard Supports
function to query any other interface. IDispatch
is a lot of overkill here. Just make a single-purpose "object holder" interface and query it. Actually, there ALREADY exists such an interface startying with Delphi 2009 (the one used to implement "AS" operator on interfaces to cast them back to obj, only make your own implementation of it), also a smilar pre-2009 intf https://mcmap.net/q/651018/-how-to-cast-a-interface-to-a-object-in-delphi –
Improve TPublishableVariantType = class(TInvokeableVariantType, IVarInstanceReference)
exists in Delphi 2007 at least, also the intf is defined in stock unit variants
, seems the best possible approach to me. Making a wrapper would be trivial excersize... –
Improve 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));
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.
IInterface
AKA IUnknown
into the variant. Then yuo can use Delphi standard Supports
function to query any other interface. IDispatch
is a lot of overkill here. Just make a single-purpose "object holder" interface and query it. Actually, there ALREADY exists such an interface startying with Delphi 2009 (the one used to implement "AS" operator on interfaces to cast them back to obj, only make your own implementation of it), also a smilar pre-2009 intf https://mcmap.net/q/651018/-how-to-cast-a-interface-to-a-object-in-delphi –
Improve TPublishableVariantType = class(TInvokeableVariantType, IVarInstanceReference)
exists in Delphi 2007 at least, also the intf is defined in stock unit variants
, seems the best possible approach to me. Making a wrapper would be trivial excersize... –
Improve 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;
varByRef or varVariant
to work properly in Delphi. –
Allyson VarByRef
wish indeed is equal to varEmpty or varByRef
- and i agree this one was a neat trick. Using explicitly impossible values erring on passive size - i like the idea. But importanly someone changed the code in 2018 and now it became VarUnknown
wioch means auto-ref-counted IInterface
not object !!! This is a very dangerous change for now any standard-compliable code would possible fail with access violation. Even while VCL TComponent
does have IInterface
implemented method offsets are DIFFERENT! –
Improve © 2022 - 2024 — McMap. All rights reserved.