Commits

Anonymous committed eb2ff2e

BUG FIX: Type Generation does not support events

Comments (0)

Files changed (9)

 Json.6.0.ReSharper.user
 Json.sln.DotSettings.user
 NuGet/
+TestResults/

Json.Tests/Json/Serialization/Internal/TypeGeneratorTest.cs

 			Assert.AreEqual(default(int), actual);
 		}
 		[TestMethod]
+		public void EventSubscription_Success()
+		{
+			var instance = TypeGenerator.Default.Generate<IInterface>();
+
+			EventHandler handler = (o, e) => { };
+
+			instance.RequiredEvent += handler;
+			instance.RequiredEvent -= handler;
+		}
+		[TestMethod]
 		public void CacheTypes_Success()
 		{
 			var instance = TypeGenerator.Default.Generate<IInterface>();

Json.Tests/Test References/IInterface.cs

 		string this[int a] { get; set; }
 		string RequiredProp { get; set; }
 		T RequiredMethod<T, U>(U str) where T : U;
+		event EventHandler RequiredEvent;
 	}
 }

Json.Tests/Test References/ImplementationClass.cs

 		{
 			return default(T);
 		}
+		public event EventHandler RequiredEvent;
 
 		public override bool Equals(object obj)
 		{

Binary file modified.

Json/Serialization/Internal/TypeGenerator.cs

 using System.Linq;
 using System.Reflection;
 using System.Reflection.Emit;
+using System.Threading;
 
 namespace Manatee.Json.Serialization.Internal
 {
 		{
 			Default = new TypeGenerator();
 			var assemblyName = new AssemblyName(AssemblyName);
-			//_assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave, @"E:\Projects\Json\Json.Tests\bin\Debug\");
-			_assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndCollect);
+			_assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave, @"E:\Projects\Manatee.Json\Json.Tests\bin\Debug\");
+			//_assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndCollect);
 			_moduleBuilder = _assemblyBuilder.DefineDynamicModule(AssemblyName, AssemblyName + ".dll");
 			_cache = new Dictionary<Type, Type>();
 		}
 			var typeBuilder = CreateType(type);
 			ImplementProperties<T>(typeBuilder);
 			ImplementMethods<T>(typeBuilder);
+			ImplementEvents<T>(typeBuilder);
 			var concreteType = typeBuilder.CreateType();
 			_cache.Add(type, concreteType);
-			//_assemblyBuilder.Save(@"Manatee.Json.DynamicTypes.dll");
+			_assemblyBuilder.Save(@"Manatee.Json.DynamicTypes.dll");
 			return (T)ConstructInstance(concreteType);
 		}
 
 			methods.AddRange(interfaceTypes.SelectMany(GetAllProperties));
 			return methods;
 		}
-		private static void ImplementSingleProperty(TypeBuilder builder, PropertyInfo property)
+		private static void ImplementSingleProperty(TypeBuilder builder, PropertyInfo propertyInfo)
 		{
 			const MethodAttributes methodAttr = MethodAttributes.Public | MethodAttributes.SpecialName |
 			                                    MethodAttributes.HideBySig | MethodAttributes.Virtual;
-			var fieldBuilder = builder.DefineField("_" + property.Name, property.PropertyType, FieldAttributes.Private);
-			var indexers = property.GetIndexParameters().Select(p => p.ParameterType).ToArray();
-			var propertyBuilder = builder.DefineProperty(property.Name, PropertyAttributes.None, property.PropertyType, indexers);
+			var fieldBuilder = builder.DefineField("_" + propertyInfo.Name, propertyInfo.PropertyType, FieldAttributes.Private);
+			var indexers = propertyInfo.GetIndexParameters().Select(p => p.ParameterType).ToArray();
+			var propertyBuilder = builder.DefineProperty(propertyInfo.Name, PropertyAttributes.None, propertyInfo.PropertyType, indexers);
 			MethodBuilder methodBuilder;
-			if (property.CanRead)
+			if (propertyInfo.CanRead)
 			{
-				methodBuilder = builder.DefineMethod(property.GetGetMethod().Name, methodAttr, property.PropertyType, indexers);
+				methodBuilder = builder.DefineMethod(propertyInfo.GetGetMethod().Name, methodAttr, propertyInfo.PropertyType, indexers);
 				var il = methodBuilder.GetILGenerator();
 				il.Emit(OpCodes.Ldarg_0);
 				il.Emit(OpCodes.Ldfld, fieldBuilder);
 				il.Emit(OpCodes.Ret);
 				propertyBuilder.SetGetMethod(methodBuilder);
-				builder.DefineMethodOverride(methodBuilder, property.GetGetMethod());
+				builder.DefineMethodOverride(methodBuilder, propertyInfo.GetGetMethod());
 			}
-			if (property.CanWrite)
+			if (propertyInfo.CanWrite)
 			{
-				methodBuilder = builder.DefineMethod(property.GetGetMethod().Name, methodAttr, null,
-				                                     indexers.Union(new[] {property.PropertyType}).ToArray());
+				methodBuilder = builder.DefineMethod(propertyInfo.GetGetMethod().Name, methodAttr, null,
+				                                     indexers.Union(new[] {propertyInfo.PropertyType}).ToArray());
 				var il = methodBuilder.GetILGenerator();
 				il.Emit(OpCodes.Ldarg_0);
 				il.Emit(OpCodes.Ldarg_1);
 				il.Emit(OpCodes.Stfld, fieldBuilder);
 				il.Emit(OpCodes.Ret);
 				propertyBuilder.SetSetMethod(methodBuilder);
-				builder.DefineMethodOverride(methodBuilder, property.GetSetMethod());
+				builder.DefineMethodOverride(methodBuilder, propertyInfo.GetSetMethod());
 			}
 		}
 		private static void ImplementMethods<T>(TypeBuilder builder)
 			methods.AddRange(interfaceTypes.SelectMany(GetAllMethods));
 			return methods;
 		}
-		private static void ImplementSingleMethod(TypeBuilder builder, MethodInfo method)
+		private static void ImplementSingleMethod(TypeBuilder builder, MethodInfo methodInfo)
 		{
 			const MethodAttributes methodAttr = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Final;
-			var types = method.GetParameters().Select(p => p.ParameterType).ToArray();
-			var methodBuilder = builder.DefineMethod(method.Name, methodAttr, method.ReturnType, types);
-			if (method.ContainsGenericParameters)
+			var types = methodInfo.GetParameters().Select(p => p.ParameterType).ToArray();
+			var methodBuilder = builder.DefineMethod(methodInfo.Name, methodAttr, methodInfo.ReturnType, types);
+			if (methodInfo.ContainsGenericParameters)
 			{
-				var genericParameters = method.GetGenericArguments().Where(p => p.IsGenericParameter).ToList();
+				var genericParameters = methodInfo.GetGenericArguments().Where(p => p.IsGenericParameter).ToList();
 				var names = genericParameters.Select(p => p.Name).ToArray();
 				var typeParameters = methodBuilder.DefineGenericParameters(names);
 				foreach (var typeParameter in typeParameters)
 				}
 			}
 			var il = methodBuilder.GetILGenerator();
-			var localBuilder = il.DeclareLocal(method.ReturnType);
+			var localBuilder = il.DeclareLocal(methodInfo.ReturnType);
 			il.Emit(OpCodes.Ldloca_S, localBuilder);
 			il.Emit(OpCodes.Initobj, localBuilder.LocalType);
 			il.Emit(OpCodes.Ldloc_0);
 			il.Emit(OpCodes.Ldloc_0);
 			il.Emit(OpCodes.Ret);
 		}
+		private static void ImplementEvents<T>(TypeBuilder builder)
+		{
+			var interfaceType = typeof(T);
+			var events = GetAllEvents(interfaceType);
+			foreach (var eventInfo in events)
+			{
+				ImplementSingleEvent(builder, eventInfo);
+			}
+		}
+		private static IEnumerable<EventInfo> GetAllEvents(Type type)
+		{
+			var events = new List<EventInfo>(type.GetEvents());
+			var interfaceTypes = type.GetInterfaces();
+			events.AddRange(interfaceTypes.SelectMany(GetAllEvents));
+			return events;
+		}
+		private static void ImplementSingleEvent(TypeBuilder builder, EventInfo eventInfo)
+		{
+			const MethodAttributes methodAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.NewSlot |
+												MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.Final;
+			var fieldBuilder = builder.DefineField("_" + eventInfo.Name, eventInfo.EventHandlerType, FieldAttributes.Private);
+			var eventBuilder = builder.DefineEvent(eventInfo.Name, EventAttributes.None, eventInfo.EventHandlerType);
+
+			var methodBuilder = builder.DefineMethod(eventInfo.GetAddMethod().Name, methodAttr, null,
+			                                         new[] {eventInfo.EventHandlerType});
+			var combineMethod = typeof (Delegate).GetMethod("Combine", new[] {typeof (Delegate), typeof (Delegate)});
+			var removeMethod = typeof (Delegate).GetMethod("Remove", new[] {typeof (Delegate), typeof (Delegate)});
+			var compareExchangeMethod = typeof (Interlocked).GetMethods()
+			                                                .Single(m => (m.Name == "CompareExchange") && m.IsGenericMethod)
+			                                                .MakeGenericMethod(eventInfo.EventHandlerType);
+			var il = methodBuilder.GetILGenerator();
+			il.DeclareLocal(eventInfo.EventHandlerType);
+			il.DeclareLocal(eventInfo.EventHandlerType);
+			il.DeclareLocal(eventInfo.EventHandlerType);
+			il.DeclareLocal(typeof (bool));
+			il.Emit(OpCodes.Ldarg_0);
+			il.Emit(OpCodes.Ldfld, fieldBuilder);
+			il.Emit(OpCodes.Stloc_0);
+			var label = il.DefineLabel();
+			il.MarkLabel(label);
+			il.Emit(OpCodes.Ldloc_0);
+			il.Emit(OpCodes.Stloc_1);
+			il.Emit(OpCodes.Ldloc_1);
+			il.Emit(OpCodes.Ldarg_1);
+			il.Emit(OpCodes.Call, combineMethod);
+			il.Emit(OpCodes.Castclass, eventInfo.EventHandlerType);
+			il.Emit(OpCodes.Stloc_2);
+			il.Emit(OpCodes.Ldarg_0);
+			il.Emit(OpCodes.Ldflda, fieldBuilder);
+			il.Emit(OpCodes.Ldloc_2);
+			il.Emit(OpCodes.Ldloc_1);
+			il.Emit(OpCodes.Call, compareExchangeMethod);
+			il.Emit(OpCodes.Stloc_0);
+			il.Emit(OpCodes.Ldloc_0);
+			il.Emit(OpCodes.Ldloc_1);
+			il.Emit(OpCodes.Ceq);
+			il.Emit(OpCodes.Ldc_I4_0);
+			il.Emit(OpCodes.Ceq);
+			il.Emit(OpCodes.Stloc_3);
+			il.Emit(OpCodes.Ldloc_3);
+			il.Emit(OpCodes.Brtrue_S, label);
+			il.Emit(OpCodes.Ret);
+			eventBuilder.SetAddOnMethod(methodBuilder);
+			builder.DefineMethodOverride(methodBuilder, eventInfo.GetAddMethod());
+
+			methodBuilder = builder.DefineMethod(eventInfo.GetRemoveMethod().Name, methodAttr, null, new[] {eventInfo.EventHandlerType});
+			il = methodBuilder.GetILGenerator();
+			il.DeclareLocal(eventInfo.EventHandlerType);
+			il.DeclareLocal(eventInfo.EventHandlerType);
+			il.DeclareLocal(eventInfo.EventHandlerType);
+			il.DeclareLocal(typeof (bool));
+			il.Emit(OpCodes.Ldarg_0);
+			il.Emit(OpCodes.Ldfld, fieldBuilder);
+			il.Emit(OpCodes.Stloc_0);
+			label = il.DefineLabel();
+			il.MarkLabel(label);
+			il.Emit(OpCodes.Ldloc_0);
+			il.Emit(OpCodes.Stloc_1);
+			il.Emit(OpCodes.Ldloc_1);
+			il.Emit(OpCodes.Ldarg_1);
+			il.Emit(OpCodes.Call, removeMethod);
+			il.Emit(OpCodes.Castclass, eventInfo.EventHandlerType);
+			il.Emit(OpCodes.Stloc_2);
+			il.Emit(OpCodes.Ldarg_0);
+			il.Emit(OpCodes.Ldflda, fieldBuilder);
+			il.Emit(OpCodes.Ldloc_2);
+			il.Emit(OpCodes.Ldloc_1);
+			il.Emit(OpCodes.Call, compareExchangeMethod);
+			il.Emit(OpCodes.Stloc_0);
+			il.Emit(OpCodes.Ldloc_0);
+			il.Emit(OpCodes.Ldloc_1);
+			il.Emit(OpCodes.Ceq);
+			il.Emit(OpCodes.Ldc_I4_0);
+			il.Emit(OpCodes.Ceq);
+			il.Emit(OpCodes.Stloc_3);
+			il.Emit(OpCodes.Ldloc_3);
+			il.Emit(OpCodes.Brtrue_S, label);
+			il.Emit(OpCodes.Ret);
+			eventBuilder.SetRemoveOnMethod(methodBuilder);
+			builder.DefineMethodOverride(methodBuilder, eventInfo.GetRemoveMethod());
+		}
 		private static object ConstructInstance(Type type)
 		{
 			return Activator.CreateInstance(type, null);
Add a comment to this file

Logo/Manatee-Json-Logo.png

Removed
Old image
Add a comment to this file

Logo/Manatee-Json-Logo.xcf

Binary file removed.

Add a comment to this file

Manatee.Json - ReadMe.docx

Binary file removed.

Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.