This article relates to Unity 2.0 (April 2010 release) and Microsoft Enterprise Library 5.0 (April 2010 release)
When using Unity with Interception and Virtual method based interception, there is an exception thrown when trying to intercept a generic class with interface constraints on the generic type(s).
Example of such a generic class that will cause an exception when intercepted:
public MyClass<T> where T : IMyInterfaceConstraint { }
The exception thrown is:
FailedSystem.ArgumentException: Cannot set parent to an interface
Looking at the Unity source code, we can find that the bug is thrown from method DefineGenericArguments of the InterceptingClassGenerator, line 17:
private static void DefineGenericArguments(TypeBuilder typeBuilder, Type baseClass) { if (!baseClass.IsGenericType) return; Type[] genericArguments = baseClass.GetGenericArguments(); GenericTypeParameterBuilder[] genericTypes = typeBuilder.DefineGenericParameters( genericArguments.Select(t => t.Name).ToArray()); for (int i = 0; i < genericArguments.Length; ++i) { genericTypes[i].SetGenericParameterAttributes(genericArguments[i].GenericParameterAttributes); foreach (Type constraint in genericArguments[i].GetGenericParameterConstraints()) { genericTypes[i].SetBaseTypeConstraint(constraint); } } }
This code has to be changed for the following:
private static void DefineGenericArguments(TypeBuilder typeBuilder, Type baseClass) { if (!baseClass.IsGenericType) return; Type[] genericArguments = baseClass.GetGenericArguments(); GenericTypeParameterBuilder[] genericTypes = typeBuilder.DefineGenericParameters( genericArguments.Select(t => t.Name).ToArray()); for (int i = 0; i < genericArguments.Length; ++i) { genericTypes[i].SetGenericParameterAttributes(genericArguments[i].GenericParameterAttributes); List<type> interfaceConstraintList = null; foreach (Type constraint in genericArguments[i].GetGenericParameterConstraints()) { if (constraint.IsClass) genericTypes[i].SetBaseTypeConstraint(constraint); else { if (interfaceConstraintList == null) interfaceConstraintList = new List<type>(); interfaceConstraintList.Add(constraint); } } if (interfaceConstraintList != null) genericTypes[i].SetInterfaceConstraints(interfaceConstraintList.ToArray()); } }
The Unity Dlls then have to be rebuilt, and all the Enterprise Library DLLs having reference to the Unity DLLs (because after rebuilding Unity, the assembly is no more strongly typed since we obviously don't have the Microsoft private key).
That's it, problem solved. Just hope this will be solved in a future release of Unity.
Comments
You can follow this conversation by subscribing to the comment feed for this post.