[68061 Closed] Test if a class supports a particular interface

I have the following Delphi code:

class function RTL.Supports (const aClass: TClass; const IID: TGUID): Boolean;
begin
  Result := aClass.GetInterfaceEntry (IID) <> nil;
end;

Is it possible to do the same with Oxygene?
I did look at ShineOn but there is no overload for testing if a class supports a specific interface.

EDIT
I am porting code from Delphi to Oxygene, thus the interfaces do not have Guids so I’m looking for an implementation of an equivalent method something along the lines of:

class method RTL.Supports (const aClass: System.Type; const IID: System.Type): Boolean;
begin
  Result := ....
end; 

you can just do “if <object> is <interface> then”, if you have a class instance. If you only have a type, i lieve you’ll need to use Reflection, eg: http://stackoverflow.com/questions/1519530/using-reflection-to-find-interfaces-implemented

That is correct, I do not have an instance at hand so the is operator is no good to me.
What I have is a reference to a System.Type which is the type MyClass where MyClass = class of MyObject

I tried this but it does not work. The interfaces that I have implemented on a class are not in the GetInterfaces array.

class method RTL.Supports <TClass, TInterface>: Boolean;
begin
  var classType: System.Type := typeOf(TClass);
  var intfType: System.Type := typeOf(TInterface); 
  if classType.IsClass and intfType.IsInterface then begin
    var interfaces: array of System.Type := classType.GetType.GetInterfaces;
    for each intf: System.Type in interfaces do begin
      if intf.Equals (intfType) then begin
        exit True;
      end;
    end;
  end;
end; 

You want something like

intfType.IsAssignableFrom(classType)

I tried this and still no luck

class method RTL.Supports <TClass, TInterface>: Boolean;
begin
  var classType: System.Type := typeOf(TClass);
  var intfType: System.Type := typeOf(TInterface); 
  if classType.IsClass and intfType.IsInterface then begin
    exit intfType.IsAssignableFrom(classType);
  end;
end;
...
  if RTL.Supports<TFoo, IFoo> then begin
      // never reached even though TFoo implements IFoo
  end;

This prints true for me:

namespace ConsoleApplication113;

interface

uses
  System.Linq;

type
  ImyItnf = public interface end;
  ConsoleApp = class(ImyItnf) 
  public
    class method Main(args: array of String);
    class method Supports <TClass, TInterface>: Boolean;
  end;

implementation

class method ConsoleApp.Supports <TClass, TInterface>: Boolean;
begin
  var classType: System.Type := typeOf(TClass);
  var intfType: System.Type := typeOf(TInterface); 
  if classType.IsClass and intfType.IsInterface then begin
    exit intfType.IsAssignableFrom(classType);
  end;
end;

class method ConsoleApp.Main(args: array of String);
begin
  Console.WriteLine('Hello World: '+Supports<ConsoleApp, ImyItnf>);
end;

end.


Ok figured it out.
If the class is declared in the implementation scope it is not assignable.
I assume because the class is private.by default if defined in the implementation scope.

So in the context of preparing my Delphi library for compilation in Oxygene I would have to move 370 class definitions into the interface area. I was hoping to maintain a single code base with an automated parser that ‘cleans’ the Delphi code and exports Oxygene compatible code. Such a big change would certainly result in maintaining two code bases.
In the Delphi library the class definitions are deliberately hidden so un-hiding them is something I want to avoid.

Any other ideas?

can you give an example of one that fails the test?

Fails

type
  IFoo = interface;

implementation

type
  TFoo = class(Object, IFoo); 

Works

type
  IFoo = interface;
  TFoo = class(Object, IFoo); 

implementation

Hrmm I can’t reprodce that locally, this works fine:

namespace ConsoleApplication113;
interface
uses
  System.Linq;

type
  ConsoleApp = class
  public
    class method Main(args: array of String);
    class method Supports <TClass, TInterface>: Boolean;
  end;

type
  IFoo = interface;



implementation

type
  TFoo = class(Object, IFoo);

class method ConsoleApp.Supports <TClass, TInterface>: Boolean;
begin
  var classType: System.Type := typeOf(TClass);
  var intfType: System.Type := typeOf(TInterface); 
  if classType.IsClass and intfType.IsInterface then begin
    exit intfType.IsAssignableFrom(classType);
  end;
end;

class method ConsoleApp.Main(args: array of String);
begin
  Console.WriteLine('Hello World: '+Supports<TFoo, IFoo>);
end;

end.

Microsoft Visual Studio Ultimate 2012
Version 11.0.50727.1 RTMREL
Microsoft .NET Framework
Version 4.5.50938
RemObjects Elements 7.1.73.1515 (TRIAL)

Your console app works fine but the function fails in my windows app.
I will do some foraging and let you know if I find something of interest.

For those who found this interesting here is the code that does work correctly for me, and also closer to what I was trying to achieve to start with. The RTL.Supports function will be used to test whether a given class supports a specific interface prior to being registered with a class factory. In turn the class factory will make new instances of objects that support the requested interface using the handy RTLClass.create method. The end goal is to have Delphi and Oxygene compatibile way of creating instances as follows: Factory.Make<IFoo>: RTLInterface;

interface

type
  RTLInterface = interface;

  RTLClass = class of RTLObject;

  RTLObject = public class (Object, RTLInterface);

  RTL = public class
  public
    class method Supports<T>(aClass: RTLClass): Boolean; where T is RTLInterface;
  end;

  IFoo = interface (RTLInterface);

implementation

type
  TFoo = class (RTLObject, IFoo)
  end;

class method RTL.Supports <T>(aClass: RTLClass): Boolean;
begin
  var classType: System.Type := aClass.ActualType;
  var intfType: System.Type := typeOf(T); 
  if assigned(classType) and classType.IsClass and intfType.IsInterface then begin
    exit intfType.IsAssignableFrom(classType);
  end;
end;

end.

The following is the project that fails to correctly evaluate if a class supports an interface.

ExampleThatFails.zip (67.3 KB)

Thanks, logged as bugs://68061: Test if a class supports a particular interface

When I compile it with the latest I get an error:

(it’s a new error but makes sense, the TNewType is more visible than TCustomType)

If i move TNewType to the implementation I get:
TCustomType supports ICustomType : True

bugs://68061 got closed as unable to reproduce for release Jul14

Agreed, so now I’m wondering why I have never seen E380. On my setup the app compiles and runs without any warnings or errors

It’s a new error that just got introduced.

Apologies, once I refocused my brain with some sleep it occurred to me that you had fixed the bug by surfacing the error as compiler error.