About Jolt.NET Libraries

Inspired by the Boost C++ libraries, Jolt.NET aims to complement the .NET Base Class Library (BCL) with algorithms, data structures, and general productivity tools. It is the hope of the authors that the features of Jolt.NET will one day be part of, or represented in the BCL and the .NET Framework.

Interface Implementations: Revisited

Yesterday I investigated stripping explicit interface implementation from the ProxyTypeBuilder as a result of my research described in this post. My preliminary conclusion is that this is the right way to go, as it will simplify some of the code and sidestep the generic interface issue.

I also started thinking about bug #27, as it relates to interface inheritance and implementation. The bug in question states that if a real subject type inherits a collection of interfaces, then the generated proxy should also inherit the same interfaces. Doing so allows you to pass the proxy reference to methods that accepted the real subject type as an interface handle.

It turns out that this is a complex problem to solve, as depicted by the following code.

public interface Ia { void f(); }
public interface Ib { void f(); }
public interface Ic { void f(); void h(); }
public interface Id<T> { T f(); }

public sealed class RealSubject : Ia, Ib, Ic, Id<int>, IDisposable
public void Dispose() { }

void Ia.f() { }
void Ib.f() { }

public void f() { }
void Ic.h() { }

int Id<int>.f() { return 0; }

public void g() { }

public interface IProxy : Ia, Ib, Ic, Id<int>, IDisposable
void g();

public sealed class Proxy : IProxy
public void Dispose() { m_t.Dispose(); }
public void f() { m_t.f(); } // Satisfies Ia, Ib, and Ic, but forwards to RealSubject.f().
public void g() { m_t.g(); }

void Ia.f() { (m_t as Ia).f(); }
void Ib.f() { (m_t as Ib).f(); }
void Ic.f() { (m_t as Ic).f(); }
int Id<int>.f() { return (m_t as Id).f(); }

void Ic.h() { (m_t as Ic).h(); }

private readonly RealSubject m_t = new RealSubject();

You will notice that the only method defined by the RealSubject is g(). All other methods implement an interface. Consequently, the only method that needs to be generated in the IProxy interface is g() since if IProxy inherits all of the interfaces inherited by RealSubject, then it will force Proxy to implement those interfaces.

The difficulty in solving this problem comes when the method f() is added to the ProxyTypeBuilder. It is o.k. for the ProxyTypeBuilder to not override any of the interface methods in Ia, Ib, and Ic, since it is still legal C# syntax. However, which interfaces should IProxy implement? If we say "all of them", then the code becomes illegal since Proxy doesn't implement Ic.h(). Infact, this problem arises when we give any method that implements an interface to the ProxyTypeBuilder. We can only add the inherited interface to IProxy once we know that all of its method implementations are satisifed.

Perhaps an interface change in ProxyTypeBuilder is required to better address this issue. In any case, I will move this bug to a post-initial release time period as I will need to think about it in order to derive the correct implementation.

Finally, the lack of this feature means that only public methods will be accepted by the ProxyTypeBuilder (which is the current implementation). Explicitly implemented interface methods require interface inheritance, which will be addressed later on. Note that the generic interface implementation issue will need to be addressed when this feature is implemented, so hopefully a patch is available by then!