static object CreateStaticProxy(Type duck, Type @interface, MissingMethods missingMethods) { if (duck == null) { throw new ArgumentNullException(nameof(duck)); } if (@interface == null) { throw new ArgumentNullException(nameof(@interface)); } if ([email protected]().IsInterface) { throw new ArgumentException($"{@interface} is not an interface"); } string assemblyName = "Ducks_Static_" + @interface.AsmName() + "_" + duck.AsmName() + ".dll"; var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(assemblyName), AssemblyBuilderAccess.Run); var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName); TypeBuilder typeBuilder = moduleBuilder.DefineType("Proxy"); foreach (var face in @interface.GetTypeInfo().GetInterfaces().Concat(@interface)) { typeBuilder.AddInterfaceImplementation(face); } var ctor = typeBuilder.DefineDefaultConstructor(Public); foreach (var face in @interface.GetTypeInfo().GetInterfaces().Concat(@interface)) { DefineMethods(typeBuilder, duck, face, missingMethods); } return(Activator.CreateInstance(typeBuilder.CreateTypeInfo().AsType())); }
public TypePair(Type from, Type to, MissingMethods missingMethods) { if (from == null) { throw new ArgumentNullException(nameof(from)); } if (to == null) { throw new ArgumentNullException(nameof(to)); } From = from; To = to; MissingMethods = missingMethods; }
/// <param name="duck">The duck</param> /// <param name="interface">the interface to cast <paramref name="duck"/></param> static Func <Delegate, object> CreateProxy(Type duck, Type @interface, MissingMethods missingMethods) { if (duck == null) { throw new ArgumentNullException(nameof(duck)); } if (@interface == null) { throw new ArgumentNullException(nameof(@interface)); } if ([email protected]) { throw new ArgumentException($"{@interface} is not an interface"); } string assemblyName = "Ducks_Instance_" + @interface.AsmName() + "_" + duck.AsmName() + ".dll"; var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(assemblyName), AssemblyBuilderAccess.Run); var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName); TypeBuilder typeBuilder = moduleBuilder.DefineType("Proxy"); foreach (var face in @interface.GetInterfaces().Concat(@interface, typeof(IDuck))) { typeBuilder.AddInterfaceImplementation(face); } var duckField = typeBuilder.DefineField("duck", duck, FieldAttributes.Private | FieldAttributes.InitOnly); var ctor = typeBuilder.DefineConstructor(duck, duckField); bool defined = false; foreach (var face in @interface.GetInterfaces().Concat(@interface)) { DefineMembers(duck, face, typeBuilder, duckField, ref defined); } var create = typeBuilder.DefineStaticCreateMethod(duck, ctor, typeof(Delegate)); typeBuilder.DefineUnwrapMethod(duckField); Type t = typeBuilder.CreateType(); return((Func <Delegate, object>)Delegate.CreateDelegate(typeof(Func <Delegate, object>), t.GetMethod("Create", BindingFlags.Static | BindingFlags.Public))); }
/// <param name="duck">The duck</param> /// <param name="interface">the interface to cast <paramref name="duck"/></param> /// <param name="missingMethods">How to handle missing methods</param> static IDuckDelegateFactory CreateProxy(Type duck, Type @interface, MissingMethods missingMethods) { if (duck == null) { throw new ArgumentNullException(nameof(duck)); } if (@interface == null) { throw new ArgumentNullException(nameof(@interface)); } if ([email protected]().IsInterface) { throw new ArgumentException($"{@interface} is not an interface"); } string assemblyName = "Ducks_Instance_" + @interface.AsmName() + "_" + duck.AsmName() + ".dll"; var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(assemblyName), AssemblyBuilderAccess.Run); var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName); TypeBuilder proxyBuilder = moduleBuilder.DefineType($"{duck.Name}_{@interface.Name}_DelegateProxy"); foreach (var face in @interface.GetInterfaces().Concat(@interface, typeof(IDuck))) { proxyBuilder.AddInterfaceImplementation(face); } var duckField = proxyBuilder.DefineField("duck", duck, FieldAttributes.Private | FieldAttributes.InitOnly); var ctor = proxyBuilder.DefineConstructor(duck, duckField); bool defined = false; foreach (var face in @interface.GetInterfaces().Concat(@interface)) { DefineMembers(duck, face, proxyBuilder, duckField, ref defined); } proxyBuilder.DefineUnwrapMethod(duckField); var factoryBuilder = CreateFactory(moduleBuilder, duck, ctor); proxyBuilder.CreateTypeInfo(); return((IDuckDelegateFactory)Activator.CreateInstance(factoryBuilder.CreateTypeInfo().AsType())); }
static void DefineMethods(TypeBuilder typeBuilder, Type duck, Type @interface, MissingMethods missingMethods) { foreach (var method in @interface.GetTypeInfo().GetMethods().Where(m => !m.IsSpecialName)) { MethodInfo duckMethod = duck.FindDuckMethod(method, PublicStatic, missingMethods); AddMethod(typeBuilder, duckMethod, method); } foreach (var prop in @interface.GetTypeInfo().GetProperties()) { var duckProp = duck.FindDuckProperty(prop, PublicStatic, missingMethods); AddProperty(typeBuilder, duckProp, prop); } foreach (var evt in @interface.GetTypeInfo().GetEvents()) { var duckEvent = duck.FindDuckEvent(evt, PublicStatic, missingMethods); AddEvent(typeBuilder, duckEvent, evt); } }
internal static object Cast(Type from, Type to, MissingMethods missingMethods) { return(proxies.GetOrAdd(new TypePair(from, to, missingMethods), pair => CreateStaticProxy(pair.From, pair.To, pair.MissingMethods))); }
internal static object Cast(Delegate from, Type to, MissingMethods missingMethods) { var factory = casts.GetOrAdd(new TypePair(from.GetType(), to, missingMethods), pair => CreateProxy(pair.From, pair.To, pair.MissingMethods)); return(factory.Create(from)); }
static void DefineMembers(Type duck, Type @interface, TypeBuilder typeBuilder, FieldBuilder duckField, MissingMethods missingMethods) { foreach (var method in @interface.GetTypeInfo().GetMethods().Where(mi => !mi.IsSpecialName)) // ignore get and set property methods { var duckMethod = duck.FindDuckMethod(method, PublicInstance, missingMethods); typeBuilder.AddMethod(duckMethod, method, duckField); } foreach (var prop in @interface.GetTypeInfo().GetProperties()) { var duckProp = duck.FindDuckProperty(prop, PublicInstance, missingMethods); AddProperty(typeBuilder, duckProp, prop, duckField); } foreach (var evt in @interface.GetTypeInfo().GetEvents()) { var duckEvent = duck.FindDuckEvent(evt, PublicInstance, missingMethods); AddEvent(typeBuilder, duckEvent, evt, duckField); } }
public static EventInfo FindDuckEvent(this Type duck, EventInfo evt, BindingFlags bindingFlags, MissingMethods missingMethods) { try { var found = duck.GetEvent(evt.Name, bindingFlags); if (found == null && missingMethods == MissingMethods.NotImplemented) { return(null); } if (found == null) { throw new InvalidCastException($"Type {duck.Name} does not have a {bindingFlags} event {evt.Name}"); } if (evt.EventHandlerType != found.EventHandlerType) { throw new InvalidCastException($"Type {duck.Name} {bindingFlags} event {evt.Name} has type {found.EventHandlerType.Name} but expected type {evt.EventHandlerType.Name}"); } return(found); } catch (AmbiguousMatchException) { throw new InvalidCastException($"Type {duck.Name} has an ambiguous match for {bindingFlags} event {evt.Name}"); } }
public static PropertyInfo FindDuckProperty(this Type duck, PropertyInfo prop, BindingFlags bindingFlags, MissingMethods missingMethods) { try { var found = duck.GetProperty(prop.Name, bindingFlags, null, prop.PropertyType, prop.ParameterTypes(), null); if (found == null && missingMethods == MissingMethods.NotImplemented) { return(null); } if (found == null) { throw new InvalidCastException($"Type {duck.Name} does not have a {bindingFlags} property {prop.Name} or parameters types do not match"); } if (prop.CanRead && !found.CanRead) { throw new InvalidCastException($"Type {duck.Name} does not have a {bindingFlags} get property {prop.Name}"); } if (prop.CanWrite && !found.CanWrite) { throw new InvalidCastException($"Type {duck.Name} does not have a {bindingFlags} set property {prop.Name}"); } return(found); } catch (AmbiguousMatchException) { throw new InvalidCastException($"Type {duck.Name} has an ambiguous match for property {prop.Name}"); //TODO: parameter list } }
public static MethodInfo FindDuckMethod(this Type duck, MethodInfo method, BindingFlags bindingFlags, MissingMethods missingMethods) { try { var found = duck.GetMethod(method.Name, bindingFlags, null, method.ParameterTypes(), null); if (found == null && missingMethods == MissingMethods.NotImplemented) { return(null); } if (found == null) { throw new InvalidCastException($"Type {duck.Name} does not have a {bindingFlags} method {method.Name}"); } return(found); } catch (AmbiguousMatchException) { throw new InvalidCastException($"Type {duck.Name} has an ambiguous match for {bindingFlags} method {method.Name}"); //TODO: parameter list } }
internal static object Cast(object from, Type to, MissingMethods missingMethods) { var func = casts.GetOrAdd(new TypePair(from.GetType(), to, missingMethods), pair => CreateProxy(pair.From, pair.To, pair.MissingMethods)); return(func(from)); }