Tuesday, March 1, 2011

Querying for an Unknown Interface Type

In this code:

TTest<IntfT: IInterface> = class
protected
  fObj : TInterfacedObject;
public
  function  GetVal: IntfT;
end;

How would I implement the GetVal function if I want it to return fObj as an IntfT?

I've tried:

result := fObj as IntfT;

and

fObj.QueryInterface(IntfT,result);

and

result := fObj as IInterface;

but nothing seems to work. This seems like such a simple thing, I keep thinking I must be missing something.

Any ideas?

EDIT

What looks the most promising to me right now is QueryInterface. Currently the compiler complains that IntfT isn't a GUID and I get the impression that if I had the appropriate GUID everything would be happy. Anyone know of a way to get the IID from an interface type that would work in this situation?

From stackoverflow
  • result := fObj as IntfT; ought to work, but apparently the compiler doesn't quite understand interfaces as generics. You should report this in QC.

    fObj.QueryInterface(IntfT,result); doesn't work because QueryInterface is a protected member of TInterfacedObject. Also, QueryInterface works by calling GetInterface, which looks for a GUID, and GUIDs and generics don't mix all that well.

    result := fObj as IInterface; does compile right for me. What problem are you having with it?

    TrespassersW : Well, son of a.... yes, it does work. In my actual code I was typecasting from an Items[] property, which should have been of an interface supporting type, but for some reason, with the generics, it didn't recognize that. Bug if I explicitly typecast my Items object to the interface supporting type, suddenly it works. Thanks.
    TrespassersW : Hmmmm... at a closer look, "result := fObj as IInterface" doesn't seem to work so well after all. It just delays the compiler error until later. When you actually attempt to use GetVal as the appropriate type, I get a compiler error saying "Incompatible types: 'ISomething' and 'IInterface'"
  • Here is the solution I came up with:

    function TTest<IntfT>.GetVal: IntfT;
    begin
      fObj.QueryInterface(GetTypeData(TypeInfo(T)).Guid,result);
    end;
    

    And that seems to work. (BTW, it works because fObj isn't really a TInterfacedObject, but a different interface implementing class that has a public QueryInterface method).

    TOndrej : Nice! But even with TInterfacedObject, you could use this: (FObj as IInterface).QueryInterface(GetTypeData(TypeInfo(IntfT)).Guid, Result);

0 comments:

Post a Comment