コード例 #1
0
        public static object Implement(Type target, IDictionary <string, Func <object[], object> > methods)
        {
            var interfaceMethods = target.GetMethods().Concat(target.GetInterfaces().SelectMany(inter => inter.GetMethods()));

            if (!interfaceMethods.All(m => methods.ContainsKey(m.Name)))
            {
                throw new ArgumentException("All methods of the specified interface must be implemented.", nameof(methods));
            }

            DynamicInterfaceMethodHandler handler = (methodInfo, arguments) => methods[methodInfo.Name](arguments);

            return(Implement(target, handler));
        }
コード例 #2
0
        public static object Implement(Type target, DynamicInterfaceMethodHandler implementer)
        {
            Type createdType;

            if (_implementerCache.ContainsKey(target.AssemblyQualifiedName))
            {
                createdType = _implementerCache[target.AssemblyQualifiedName];
            }
            else
            {
                createdType = CreateImplementerType(target, implementer);
                _implementerCache[target.AssemblyQualifiedName] = createdType;
            }

            var constructor = createdType.GetConstructor(new Type[] { typeof(DynamicInterfaceMethodHandler) });

            return(constructor.Invoke(new object[] { implementer }));
        }
コード例 #3
0
        private static Type CreateImplementerType(Type target, DynamicInterfaceMethodHandler implementer)
        {
            if (!target.IsInterface)
            {
                throw new ArgumentException("target must be an interface type.");
            }
            var name        = $"dynImplement({RandomEx.GetString(ranLength)})_" + target.Name;
            var typeBuilder = modBuilder.DefineType(name, TypeAttributes.Public | TypeAttributes.Class);

            typeBuilder.AddInterfaceImplementation(target);

            var implementerField = typeBuilder.DefineField("_implementer", typeof(DynamicInterfaceMethodHandler), FieldAttributes.Private);

            var constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public,
                                                                   CallingConventions.Standard | CallingConventions.HasThis,
                                                                   new Type[] { typeof(DynamicInterfaceMethodHandler) });

            // emit constructor
            var constructorIl = constructorBuilder.GetILGenerator();

            constructorIl.Emit(OpCodes.Ldarg_0);
            constructorIl.Emit(OpCodes.Ldarg_1);
            constructorIl.Emit(OpCodes.Stfld, implementerField);
            constructorIl.Emit(OpCodes.Ret);

            string debugPath          = null;
            ISymbolDocumentWriter doc = null;

            if (emitSymbols)
            {
                debugPath = Path.GetTempFileName();
                doc       = modBuilder.DefineDocument(debugPath, Guid.Empty, Guid.Empty, Guid.Empty);
            }

            // implement all interface methods.
            Dictionary <string, MethodBuilder> builders = new Dictionary <string, MethodBuilder>();
            var methods = target.GetMethods().Concat(target.GetInterfaces().SelectMany(inter => inter.GetMethods()));

            foreach (var method in methods)
            {
                if (emitSymbols)
                {
                    File.AppendAllText(debugPath, ".method " + method.Name + Environment.NewLine);
                }

                var methodParamaters = method.GetParameters().Select(p => p.ParameterType).ToArray();
                var methodBuilder    = typeBuilder.DefineMethod(method.Name, MethodAttributes.Public | MethodAttributes.Virtual, method.CallingConvention,
                                                                method.ReturnType, methodParamaters);

                builders[method.Name] = methodBuilder;

                var methodIl = emitSymbols
                    ? (ILGeneratorInterface) new DebuggableILGenerator(methodBuilder.GetILGenerator(), doc, debugPath)
                    : new StandardILGenerator(methodBuilder.GetILGenerator());

                var objLocalIndex = methodIl.DeclareLocal(typeof(object[])).LocalIndex;
                var retIsOk       = methodIl.DefineLabel();

                // create new object[] to hold paramaters and store it to local
                methodIl.Emit(OpCodes.Ldc_I4, methodParamaters.Length);
                methodIl.Emit(OpCodes.Newarr, typeof(object));
                methodIl.Emit(OpCodes.Stloc, objLocalIndex);

                // fill object array with method parameters
                for (int i = 0; i < methodParamaters.Length; i++)
                {
                    methodIl.Emit(OpCodes.Ldloc, objLocalIndex);
                    methodIl.Emit(OpCodes.Ldc_I4, i);
                    methodIl.Emit(OpCodes.Ldarg, i + 1);
                    if (methodParamaters[i].IsValueType)
                    {
                        methodIl.Emit(OpCodes.Box, methodParamaters[i]);
                    }
                    methodIl.Emit(OpCodes.Stelem_Ref);
                }

                // load current delegate, MethodInfo and object array to the stack
                methodIl.Emit(OpCodes.Ldarg_0);
                methodIl.Emit(OpCodes.Ldfld, implementerField);
                methodIl.Emit(OpCodes.Ldtoken, method);
                methodIl.Emit(OpCodes.Call, typeof(MethodBase).GetMethod("GetMethodFromHandle", new[] { typeof(RuntimeMethodHandle) }));
                methodIl.Emit(OpCodes.Castclass, typeof(MethodInfo));
                methodIl.Emit(OpCodes.Ldloc, objLocalIndex);

                // call it.
                methodIl.Emit(method.IsFinal ? OpCodes.Call : OpCodes.Callvirt, typeof(DynamicInterfaceMethodHandler).GetMethod("Invoke"));

                // handle return type mismatches.
                if (method.ReturnType == typeof(void))
                {
                    methodIl.Emit(OpCodes.Ldnull);
                    // if the last two stack elements are equal (ldnull and delegate result) goto return statement.
                    methodIl.Emit(OpCodes.Beq, retIsOk);
                    // else throw exception
                    methodIl.Emit(OpCodes.Ldstr,
                                  "Method return type mismatch: The implementing dynamic delegate tried to return a non-null value, " +
                                  "when the actual return value is void.");
                    methodIl.Emit(OpCodes.Newobj, typeof(TargetException).GetConstructor(new Type[] { typeof(string) }));
                    methodIl.Emit(OpCodes.Throw);
                }
                else
                {
                    // check the value for null, if its null just return it
                    methodIl.Emit(OpCodes.Dup);
                    methodIl.Emit(OpCodes.Ldnull);
                    methodIl.Emit(OpCodes.Beq, retIsOk);

                    methodIl.Emit(OpCodes.Dup);
                    methodIl.Emit(OpCodes.Callvirt, typeof(object).GetMethod("GetType", BindingFlags.Instance | BindingFlags.Public));
                    methodIl.EmitType(method.ReturnType, false);
                    // if the last two stack elements are equal (getType result and the returntype) goto return statement
                    methodIl.Emit(OpCodes.Callvirt, typeof(Type).GetMethod("Equals", new Type[] { typeof(Type) }));
                    methodIl.Emit(OpCodes.Ldc_I4_1);
                    methodIl.Emit(OpCodes.Beq, retIsOk);

                    methodIl.Emit(OpCodes.Ldstr,
                                  "Method return type mismatch: The implementing dynamic delegate tried to return a type that does not " +
                                  "match the return type of this method.");
                    methodIl.Emit(OpCodes.Newobj, typeof(TargetException).GetConstructor(new Type[] { typeof(string) }));
                    methodIl.Emit(OpCodes.Throw);
                }

                methodIl.MarkLabel(retIsOk);
                if (method.ReturnType.IsValueType && method.ReturnType != typeof(void))
                {
                    methodIl.Emit(OpCodes.Unbox_Any, method.ReturnType);
                }
                methodIl.Emit(OpCodes.Ret);
            }

            // create properties and match them up to appropriate methods.
            var properties = target.GetProperties().Concat(target.GetInterfaces().SelectMany(inter => inter.GetProperties()));

            foreach (var prop in properties)
            {
                var property = typeBuilder.DefineProperty(prop.Name, PropertyAttributes.HasDefault, prop.PropertyType, Type.EmptyTypes);
                if (builders.ContainsKey("get_" + prop.Name))
                {
                    property.SetGetMethod(builders["get_" + prop.Name]);
                }
                if (builders.ContainsKey("set_" + prop.Name))
                {
                    property.SetSetMethod(builders["set_" + prop.Name]);
                }
            }

            return(typeBuilder.CreateType());
        }