예제 #1
0
        private TBase CreateInstance()
        {
            var typeBuilder = _moduleBuilder.DefineType(_typeName);

            typeBuilder.SetParent(typeof(TBase));
            var implementationField = typeBuilder.DefineField("__implementation", typeof(IImplementation), FieldAttributes.Private);
            var baseConstructor     = typeof(TBase).GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { }, null);

            // Constructor
            var method = typeBuilder.DefineMethod(".ctor", MethodAttributes.Public | MethodAttributes.HideBySig);

            method.SetReturnType(typeof(void));
            method.SetParameters(typeof(IImplementation));
            method.DefineParameter(1, ParameterAttributes.None, "implementation");
            var constructorWriter = method.GetILGenerator();

            // Writing body
            constructorWriter.Emit(OpCodes.Ldarg_0);
            constructorWriter.Emit(OpCodes.Call, baseConstructor);
            constructorWriter.Emit(OpCodes.Nop);
            constructorWriter.Emit(OpCodes.Nop);
            constructorWriter.Emit(OpCodes.Ldarg_0);
            constructorWriter.Emit(OpCodes.Ldarg_1);
            constructorWriter.Emit(OpCodes.Stfld, implementationField);
            constructorWriter.Emit(OpCodes.Nop);
            constructorWriter.Emit(OpCodes.Ret);

            _implementation = new RuntimeImplementation();

            // Other methods
            foreach (var contributor in _contributors)
            {
                contributor.Contribute(typeBuilder, implementationField, _implementation);
            }

            var type = typeBuilder.CreateType();

            return((TBase)Activator.CreateInstance(type, _implementation));
        }
        void ITypeContributor.Contribute(TypeBuilder typeBuilder, FieldBuilder implementationField, RuntimeImplementation delegatedImplementation)
        {
            // Define the method
            var methodBuilder = typeBuilder.DefineMethod(_name, _accessibility | MethodAttributes.HideBySig);

            methodBuilder.SetReturnType(_callback.Method.ReturnType);
            methodBuilder.SetParameters(_callback.Method.GetParameters().Select(x => x.ParameterType).ToArray());

            // Define attributes
            foreach (var attribute in _attributes)
            {
                var types         = attribute.Value.Select(x => x.GetType()).ToArray();
                var attributeCtor = attribute.Key.GetConstructor(types);
                methodBuilder.SetCustomAttribute(
                    new CustomAttributeBuilder(attributeCtor, attribute.Value)
                    );
            }

            // Define parameters
            var parameters = new List <ParameterBuilder>();

            foreach (var param in _callback.Method.GetParameters())
            {
                parameters.Add(methodBuilder.DefineParameter(param.Position + 1, ParameterAttributes.None, param.Name));
            }

            // Prepare the implementation
            var bodyWriter = methodBuilder.GetILGenerator();

            bodyWriter.Emit(OpCodes.Ldarg_0);
            bodyWriter.Emit(OpCodes.Ldfld, implementationField);
            bodyWriter.Emit(OpCodes.Ldstr, _name);

            // Build the array of objects
            var arguments = bodyWriter.DeclareLocal(typeof(object[]));

            bodyWriter.Emit(OpCodes.Ldc_I4, parameters.Count);
            bodyWriter.Emit(OpCodes.Newarr, typeof(object));
            bodyWriter.Emit(OpCodes.Stloc, arguments);

            // Set the array
            foreach (var parameter in _callback.Method.GetParameters())
            {
                bodyWriter.Emit(OpCodes.Ldloc, arguments);
                bodyWriter.Emit(OpCodes.Ldc_I4, parameter.Position);
                bodyWriter.Emit(OpCodes.Ldarg, parameter.Position + 1);
                if (parameter.ParameterType.IsValueType)
                {
                    bodyWriter.Emit(OpCodes.Box, parameter.ParameterType);
                }
                bodyWriter.Emit(OpCodes.Stelem_Ref);
            }

            // Call Invoke and return the result
            bodyWriter.Emit(OpCodes.Ldloc, arguments);
            bodyWriter.EmitCall(OpCodes.Callvirt, typeof(IImplementation).GetMethod("Invoke"), new Type[0]);
            bodyWriter.Emit(OpCodes.Unbox_Any, _callback.Method.ReturnType);
            bodyWriter.Emit(OpCodes.Stloc_0);
            bodyWriter.Emit(OpCodes.Ldloc_0);
            bodyWriter.Emit(OpCodes.Ret);

            delegatedImplementation.RegisterCallback(_name, methodBuilder,
                                                     args =>
            {
                _wasCalled = true;
                try
                {
                    return(_callback.DynamicInvoke(args));
                }
                catch (TargetInvocationException ex)
                {
                    throw ex.InnerException;
                }
            }
                                                     );
        }