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!

Frustration with Reflection.Emit API

Over the past few months, I've been working on adding generics support to the Jolt.Testing library. I've been travelling too, so I haven't had as much time as I would have liked to spend on development.

I'm currently focusing on generic type definitions (generic method definitions will come later). For a given generic real subject type, the ProxyTypeBuilder needs to generate a generic interface and generic proxy type that match in number of arguments. Furthermore, the proxy's arguments must specialize the interface, and the interface must carry the same constraints as the real subject type. These requirements are demonstrated by the following example.



public class UserType<A,B,C>

where A : class

where B : struct

where C : A

{

bool Method() { return true; }

}



public interface IUserType<A,B,C>

where A : class

where B : struct

where C : A

{

bool Method();

}



public sealed class UserTypeProxy<Q,R,S> : IUserType<Q,R,S>

{

bool IUserType<Q,R,S>.Method() { return m_realSubjectType.Method(); }

private readonly UserType m_realSubjectType = new UserType<Q,R,S>();

}




In writing the code to implement this type of code generation, I believe I found a bug in the Reflection.Emit API. For reference, here is the code that I believe should emit the class interface and proxy relationship.


void CreateTypes(ModuleBuilder module)

{

TypeBuilder contractInterface = module.DefineType("IUserType", TypeAttributes.Public TypeAttributes.Interface TypeAttributes.Abstract TypeAttributes.AutoClass TypeAttributes.AnsiClass);

contractInterface.DefineGenericParameters("A", "B", "C");

MethodBuilder interfaceMethod = contractInterface.DefineMethod("Method",

MethodAttributes.Abstract MethodAttributes.HideBySig MethodAttributes.NewSlot MethodAttributes.Virtual MethodAttributes.Public,

typeof(bool), Type.EmptyTypes);



TypeBuilder implementationType = module.DefineType("UserTypeProxy", TypeAttributes.Public TypeAttributes.Sealed TypeAttributes.AutoClass TypeAttributes.AnsiClass TypeAttributes.BeforeFieldInit);

GenericTypeParameterBuilder[] implementationParams = implementationType.DefineGenericParameters("Q", "R", "S");

implementationType.DefineDefaultConstructor(MethodAttributes.Public MethodAttributes.SpecialName MethodAttributes.RTSpecialName);

MethodBuilder implementationMethod = implementationType.DefineMethod(contractInterface.FullName + "<Q,R,S>.Method",

MethodAttributes.Private MethodAttributes.HideBySig MethodAttributes.NewSlot MethodAttributes.Virtual MethodAttributes.Final,

typeof(bool), Type.EmptyTypes);



ILGenerator ilgen = implementationMethod.GetILGenerator();

ilgen.Emit(OpCodes.Ldc_I4_0);

ilgen.Emit(OpCodes.Ret);



Type specializedContract = contractInterface.CreateType().MakeGenericType(

implementationParams[0], implementationParams[1], implementationParams[2]);

implementationType.AddInterfaceImplementation(specializedContract);

implementationType.DefineMethodOverride(implementationMethod, interfaceMethod);

contractInterface.CreateType();

implementationType.CreateType();

}




Unfortunately, executing this code yields the following exception.

System.TypeLoadException : Type 'UserTypeProxy' from assembly 'test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' tried to override method 'IUserType.Method' but does not implement or inherit that method.

I’ve done a considerable amount of experimenting with this code, and I’m no longer sure that I have implemented the routine correctly. The error message is confusing, because the code sure looks like it is creating a method override for a method that exists. What as more confusing is the the documentation for DefineMethodOverride, which states that the method call is not needed when overriding a base-class or interface method. However, I’ve found this to be untrue when explicitly implementing an interface. Also, the above routine works as expected when I removed the generic parameters from the routine, including the MakeGenericType call; you will notice that this case is almost identical to the code path that is currently checked in for non-generic types.

My research carried me to this bug report, which is very similar in nature to my issue, but it is unclear whether the bug is fixed in .NET 3.5. A look at mscorlib.dll shows a version of 2.0.0.0, which hasn't changed since the release of .NET 2.0 so the answer is likely "not fixed".


If there is a bug in the Reflection.Emit API, then this is a dissapointing setback as the bug is unlikely to be resolved in the near-term. In that time period, I would have to restrict the code generation to implement interfaces implicitly and doing so would limit the allowable methods from a real subject type to those that do not override another via an explicit interface implementation.


public class RealSubjectType : IDisposable

{

// One of these methods will be unavailable in IRealSubjectTypeProxy.

void IDisposable.Dispose() { /* do something */ }

public void Dispose() { /* do something else */ }

}




In the mean time, I'll keep tinkering with the code and determine if it is worthwhile to continue with the approach of explicit interface implementation. Who knows, maybe a reader will point out the fault with my current code generation implementation? :)