Afraid to ask a stupid question, but both Method.Invoke() cases in this example should not work?
Afraid to ask a stupid question, but both Method.Invoke() cases in this example should not work?
https://gist.github.com/dipold/731f6262e208ea65e4b1211795ddea36
https://gist.github.com/dipold/731f6262e208ea65e4b1211795ddea36
Dont be affraid. This is not SO :)
ReplyDeleteFirst one works fine because LMethod.Invoke is expecting a a TFoo reference, and NativeUInt(TFoo(Foo)) = NativeUInt(TObject(Foo)) = NativeUInt((Foo as TObject)). The second one does not because LMethod.Invoke is now expecting a IFoo, and an interface pointer doesn't point to the same thing as a reference to the implementing object, which is what the 'as TObject' cast (really implicit getter method, in effect) returns.
ReplyDeleteIn the second line you are gettint thw pointer of ans interface method but invoking it with a tobje t, you shoukd invoke it using IFoo instead of casting it to TObject
ReplyDeleteBut there is no overloaded version of 'Invoke' that can be called with IFoo or IInterface
ReplyDelete/sub
ReplyDeleteRafael Dipold You need to box the interface reference into a TValue first, and pass that:
ReplyDeleteWriteln(LMethod.Invoke(TValue.From(LFoo), []).AsString);
Thanks! I had tried this before but I think because of the lack of the {$ RTTI} directive it did not work...
ReplyDeleteRafael Dipold Won't have been that, assuming you were calling the interface method - what's important is that the interface is declared with RTTI enabled (i.e., with {$M+}), not the implementing object. Your example code demonstrates this - remove the {$RTTI} directive and the initial object reference version of the Invoke call, add TValue boxing to the interface reference version of the Invoke call, and it will (still) work.
ReplyDeleteOne small thing to be careful of is not being lazy in the TValue.From call and failing to explicitly specify the interface type - if you take the short cut and accidentally box (say) a IInterface reference instead of IFoo, you'll get an access violation when Invoke'ing again, due to pointing to the wrong v-table.
Chris Rolliston So for better agnostic way is to either call the top most inherited IInterface type that we know has that method. Or its better to cast to TObject?
ReplyDeleteFrancisco Armando Dueñas RodrÃguez Well, it's not a matter of better vs. worse, rather of two different things. If you are ostensibly invoking an interface via RTTI, but (as an 'optimisation') casting to TObject and invoking the implementing methods directly, then you'll be introducing implicit dependencies. E.g., like requiring the implementing object to not use any form of interface delegation. Or, requiring it to have RTTI added to the interface-implementing methods, which will fall foul of the convention of using protected visibility for interface implementations and the fact protected methods don't get RTTI by default.
ReplyDelete