Bug http://entityframework.codeplex.com/workitem/184 talks about enabling JSON serialization by hidding _entityWrapper. We also have a few other strange things in POCO proxies, like the RelationshipManager property. We can easily further simplify how the type looks to POCO serializers by makign the implementation of the interfaces explicit. Here is the code we have to add in the IPOCOImplementor:
// Implement IEntityWithChangeTracker.SetChangeTracker(IEntityChangeTracker changeTracker)
MethodBuilder setChangeTracker = typeBuilder.DefineMethod("IEntityWithChangeTracker.SetChangeTracker", MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final,
typeof(void), new Type[] { typeof(IEntityChangeTracker) });
generator = setChangeTracker.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Stfld, _changeTrackerField);
generator.Emit(OpCodes.Ret);
typeBuilder.DefineMethodOverride(setChangeTracker, typeof(IEntityWithChangeTracker).GetMethod("SetChangeTracker"));
// Implement IEntityWithRelationships.get_RelationshipManager
_getRelationshipManager = typeBuilder.DefineMethod("IEntityWithRelationships.get_RelationshipManager", MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.SpecialName | MethodAttributes.Virtual | MethodAttributes.Final,
typeof(RelationshipManager), Type.EmptyTypes);
ILGenerator generator = _getRelationshipManager.GetILGenerator();
Label trueLabel = generator.DefineLabel();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, _relationshipManagerField);
generator.Emit(OpCodes.Brtrue_S, trueLabel);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Call, s_CreateRelationshipManager);
generator.Emit(OpCodes.Stfld, _relationshipManagerField);
generator.MarkLabel(trueLabel);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, _relationshipManagerField);
generator.Emit(OpCodes.Ret);
relationshipManagerProperty.SetGetMethod(_getRelationshipManager);
typeBuilder.DefineMethodOverride(_getRelationshipManager, typeof(IEntityWithRelationships).GetMethod("get_RelationshipManager"));
Notice the private methods and the call to DefineMethodOverride. This allows to implement interface members explicitly.
Doing this is a minor breacking change in two ways:
1. Serialization format changes: the extra members you used to get weren't very useful, but it is a change anyway.
2. Any code that relies on the interface members being declared directly in the proxy type will break. There are no compelling code patterns that do this, e.g. given a proxy instance, it is easier to cast it to the appropriate interface and invoke a member on that, however it is a change anyway.
// Implement IEntityWithChangeTracker.SetChangeTracker(IEntityChangeTracker changeTracker)
MethodBuilder setChangeTracker = typeBuilder.DefineMethod("IEntityWithChangeTracker.SetChangeTracker", MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final,
typeof(void), new Type[] { typeof(IEntityChangeTracker) });
generator = setChangeTracker.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Stfld, _changeTrackerField);
generator.Emit(OpCodes.Ret);
typeBuilder.DefineMethodOverride(setChangeTracker, typeof(IEntityWithChangeTracker).GetMethod("SetChangeTracker"));
// Implement IEntityWithRelationships.get_RelationshipManager
_getRelationshipManager = typeBuilder.DefineMethod("IEntityWithRelationships.get_RelationshipManager", MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.SpecialName | MethodAttributes.Virtual | MethodAttributes.Final,
typeof(RelationshipManager), Type.EmptyTypes);
ILGenerator generator = _getRelationshipManager.GetILGenerator();
Label trueLabel = generator.DefineLabel();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, _relationshipManagerField);
generator.Emit(OpCodes.Brtrue_S, trueLabel);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Call, s_CreateRelationshipManager);
generator.Emit(OpCodes.Stfld, _relationshipManagerField);
generator.MarkLabel(trueLabel);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, _relationshipManagerField);
generator.Emit(OpCodes.Ret);
relationshipManagerProperty.SetGetMethod(_getRelationshipManager);
typeBuilder.DefineMethodOverride(_getRelationshipManager, typeof(IEntityWithRelationships).GetMethod("get_RelationshipManager"));
Notice the private methods and the call to DefineMethodOverride. This allows to implement interface members explicitly.
Doing this is a minor breacking change in two ways:
1. Serialization format changes: the extra members you used to get weren't very useful, but it is a change anyway.
2. Any code that relies on the interface members being declared directly in the proxy type will break. There are no compelling code patterns that do this, e.g. given a proxy instance, it is easier to cast it to the appropriate interface and invoke a member on that, however it is a change anyway.