public static InterfaceDescriptor Get(Type type) { if (!Cache.TryGetValue(type, out var desc)) { Cache.TryAdd(type, desc = new InterfaceDescriptor(type)); } return(desc); }
private static EntangledTypeProxyDescriptor ConstructLocalProxy <T>() where T : class/*, IEntangledObject*/ { var typeInfo = typeof(T).GetTypeInfo(); if (!typeInfo.IsInterface || !typeInfo.IsPublic) { throw new ArgumentException("The provided type must be a public interface"); } var elo = typeof(EntangledLocalObjectBase); var desc = new InterfaceDescriptor(typeof(T)); var guid = typeInfo.GUID; var type = DynamicAssembly.DynamicModule.DefineType($"T{guid.ToString()}", TypeAttributes.Class | TypeAttributes.Public, elo); type.AddInterfaceImplementation(typeof(T)); var executeMethod = elo.GetMethod("ExecuteMethod", BindingFlags.Public | BindingFlags.Instance); var executeMethodVoid = elo.GetMethod("ExecuteMethodVoid", BindingFlags.Public | BindingFlags.Instance); var executeMethodSync = elo.GetMethod("ExecuteMethodSync", BindingFlags.Public | BindingFlags.Instance); var executeMethodVoidSync = elo.GetMethod("ExecuteMethodVoidSync", BindingFlags.Public | BindingFlags.Instance); type.FillBaseConstructors(elo); foreach (var methods in desc.Methods) { int methodOverloadId = 0; foreach (var method in methods.Value) { var parameters = method.Method.GetParameters(); var m = type.DefineMethod(method.Method.Name, MethodAttributes.Public | MethodAttributes.Virtual, method.Method.CallingConvention, method.Method.ReturnType, method.Method.GetParameters().Select(p => p.ParameterType).ToArray()); var i = m.GetILGenerator(); i.Emit(OpCodes.Ldarg_0); i.EmitLdci4(methodOverloadId++); i.Emit(OpCodes.Ldstr, method.Method.Name); //emit the object[] array to hold the parameters if ((parameters?.Length ?? 0) == 0) { i.Emit(OpCodes.Ldnull); } else { i.EmitLdci4((byte)parameters.Length); i.Emit(OpCodes.Newarr, typeof(object)); for (byte l = 0; l < parameters.Length; l++) { i.Emit(OpCodes.Dup); i.EmitLdci4(l); i.EmitLdarg((byte)(l + 1)); if (parameters[l].ParameterType.GetTypeInfo().IsValueType) { i.Emit(OpCodes.Box, parameters[l].ParameterType); } i.Emit(OpCodes.Stelem_Ref); } } if (method.RealReturnType == typeof(void)) { i.Emit(OpCodes.Call, method.IsAsync ? executeMethodVoid : executeMethodVoidSync); } else { i.Emit(OpCodes.Call, (method.IsAsync ? executeMethod : executeMethodSync).MakeGenericMethod(method.RealReturnType)); } i.Emit(OpCodes.Ret); //important: OVERRIDE THE INTERFACE [abstract] IMPLEMENTATION type.DefineMethodOverride(m, method.Method); } } //implement getters var generatedProperties = new Queue <string>(); foreach (var propItem in desc.Properties) { var prop = propItem.Value.Property; var baseProp = typeof(EntangledLocalObjectBase).GetProperty(propItem.Key, BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.Public); if (baseProp != null && !baseProp.GetGetMethod().IsAbstract) { continue; } var definedGetter = prop.GetGetMethod(); var field = type.DefineField($"_{prop.Name}", prop.PropertyType, FieldAttributes.Private); propItem.Value.BackingField = field; var getProp = type.DefineProperty(prop.Name, PropertyAttributes.None, prop.PropertyType, null); var getter = type.DefineMethod($"get_{prop.Name}", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Virtual, definedGetter.ReturnType, null); var il = getter.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, field); il.Emit(OpCodes.Ret); getProp.SetGetMethod(getter); type.DefineMethodOverride(getter, definedGetter); generatedProperties.Enqueue(propItem.Key); } foreach (var ev in desc.Events) { type.ImplementEvent(ev.Value.Event.DeclaringType.GetTypeInfo(), ev.Key); } var result = new EntangledTypeProxyDescriptor { GeneratedType = type.CreateTypeInfo().AsType(), Interface = desc }; foreach (var ev in desc.Events) { ev.Value.BackingField = result.GeneratedType.GetField(ev.Key, BindingFlags.NonPublic | BindingFlags.Instance); ev.Value.InvokerDelegate = CreateEventInvokerDelegate(type, ev.Value, typeof(T)); } while (generatedProperties.Any()) { var prop = generatedProperties.Dequeue(); desc.Properties[prop].BackingField = result.GeneratedType.GetField($"_{prop}", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); } return(result); }