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

Comments

  1. First 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.

    ReplyDelete
  2. In 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

    ReplyDelete
  3. But there is no overloaded version of 'Invoke' that can be called with IFoo or IInterface

    ReplyDelete
  4. Rafael Dipold You need to box the interface reference into a TValue first, and pass that:
    Writeln(LMethod.Invoke(TValue.From(LFoo), []).AsString);

    ReplyDelete
  5. Thanks! I had tried this before but I think because of the lack of the {$ RTTI} directive it did not work...

    ReplyDelete
  6. Rafael 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.

    One 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.

    ReplyDelete
  7. 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?

    ReplyDelete
  8. Francisco 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

Post a Comment