ASP.NET Hosting

Delphi implements keyword (or dynamic interface integration) (or introduction)

I guess that my next feature request for eXtensible C# (or idea at least) would be the ability to add methods (and by extension any kind of members...) to a class. By using an attribute we could add one or a set of methods to classes.

This could become even more useful if XC# provided us with the ability to define new interface implementations on classes. This would mimic the Delphi implements keword.

Here is a small explaination of what this keyword does in Delphi:

Dynamic aggregation of interfaces is not supported by the CLR, because it cannot be statically verified. In Delphi for .NET, all interfaces must be declared on the type. Dynamic aggregation is provided by the implements keyword, as the following code illustrates.

program Project1;

type
  i = interface
    procedure Wombat;
  end;

  TA = class(TInterfacedObject, i)
    procedure Wombat;
  end;

  TC = class(TInterfacedObject, i)
    fa: TA;
    property a: TA read fa implements i;
  end;

{ TA }

procedure TA.Wombat;
begin

end;

begin

end.

This is something that is really missing in .NET. In .NET, if you have a bunch of objects that must implement an interface, you have to implement every method of the interface in every object. In Delphi, you just have to implement the interface in one object (let's call it an interface helper), then say that all the objects that must implement that interface are using this interface helper.

With an XC# attribute, it could look like this:
interface IMyInterface
{
  void method1();
}
 
class MyInterfaceHelper : IMyInterface
{
  void method1()
  {
    // do something
  }
}
 
[Implements(typeof(IMyInterface), typeof(MyInterfaceHelper))]
class MyClass1
{
}
 
[Implements(typeof(IMyInterface), typeof(MyInterfaceHelper))]
class MyClass2
{
}
This way, the behavior of MyClass1 and MyClass2 objects are the same regarding the IMyTypeInterface, and we don't have to duplicate code or redeclare every method of the IMyInterface interface in every class.
 
Maybe there are existing ways to do this in .NET? I'd be curious to know how you solve this kind of situation...
 
Update: I just realized that AspectJ does that for Java through what it calls introduction.

1 Comment

  • I thought I had it with this...

    //Interface

    public interface IGreeting

    {

    void SayHelloTo(string name);

    }

    //Implementor

    public class GreetingImpl : IGreeting

    {

    public void SayHelloTo(string name)

    {

    Console.WriteLine("Hello " + name);

    }

    }

    //Some magic

    public interface IWrappable<T>

    {

    T Wrapper { get; }

    }

    //The consuming class

    public class MyClass1 : IWrappable<IGreeting>

    {

    #region Implements IGreeting

    IGreeting IGreetingImpl = new GreetingImpl();

    IGreeting IWrappable<IGreeting>.Wrapper

    {

    get { return IGreetingImpl; }

    }

    public static explicit operator IGreeting(MyClass1 instance)

    {

    return ((IWrappable<IGreeting>)instance).Wrapper;

    }

    #endregion

    }

    Looks a bit long winded, but easy enough to do with a template.  However I get the following error...

    "user-defined conversions to or from an interface are not allowed"

    That's a shame, isn't it :)  Although without the explicit/implicit casting you might still find this useful for passing an API interface to a Dynamic Runtime Language to stop it accessing a property defined as read-only in the interface as a read/write property by dynamically looking up the property on the implementing type.

    public static class IWrappableHelper

    {

    public static TInterface GetWrapper<TSource, TInterface>(this TSource instance)

    where TSource : IWrappable<TInterface>

    where TInterface : class

    {

    if (instance == null)

    return null;

    return instance.Wrapper;

    }

    }

    Then you can do this

    var apiImpl = myClass1Instance.GetWrapper<MyClass1, IGreeting>();

    //now pass apiImpl to the DLR instead of apiImpl

Comments have been disabled for this content.