Beispiel #1
0
        public static T Create <T>(string objectId, IProxyClient client)
        {
            ;
            if (_runtimeProxyTypes.ContainsKey(typeof(T)))
            {
                return((T)Activator.CreateInstance(_runtimeProxyTypes[typeof(T)], objectId, client));
            }

            // Verify type is interface
            if (!typeof(T).IsInterface)
            {
                throw new InvalidOperationException("Generic argument must be an interface.");
            }

            TypeBuilder typeBuilder = _moduleBuilder.DefineType($"{typeof(T).Name}Proxy", TypeAttributes.Public);

            // Define parent and interface
            typeBuilder.SetParent(typeof(RuntimeProxy));
            typeBuilder.CreatePassThroughConstructors(typeof(RuntimeProxy));
            typeBuilder.AddInterfaceImplementation(typeof(T));

            // Implement events
            foreach (var eventInfo in ObjectDescriptor.GetEvents <T>())
            {
                Expression <Func <RuntimeTypeHandle, object> > getTypeFromHandle = t => Type.GetTypeFromHandle(t);
                EventBuilder eventBuilder      = typeBuilder.DefineEvent(eventInfo.Value.Name, eventInfo.Value.Attributes, eventInfo.Value.EventHandlerType);
                FieldBuilder eventFieldBuilder = typeBuilder.DefineField($"_{eventInfo.Value.Name}", eventInfo.Value.EventHandlerType, FieldAttributes.Private);

                // Implement event handler add method
                // add { ... }
                {
                    MethodInfo    addMethodInfo = eventInfo.Value.GetAddMethod();
                    MethodBuilder getMb         = typeBuilder.DefineMethod(addMethodInfo.Name, MethodAttributes.Public | MethodAttributes.Virtual, typeof(void), new Type[] { eventInfo.Value.EventHandlerType });
                    ILGenerator   ilGenerator   = getMb.GetILGenerator();

                    Type         ehType   = eventInfo.Value.EventHandlerType;
                    LocalBuilder typeLb   = ilGenerator.DeclareLocal(typeof(Type), true);
                    LocalBuilder objectLb = ilGenerator.DeclareLocal(typeof(object), true);
                    LocalBuilder retLb    = ilGenerator.DeclareLocal(typeof(bool), true);

                    // _event += value;
                    Expression <Func <Delegate, object> > combine = d => Delegate.Combine(d, d);
                    ilGenerator.Emit(OpCodes.Ldarg_0);
                    ilGenerator.Emit(OpCodes.Ldarg_0);
                    ilGenerator.Emit(OpCodes.Ldfld, eventFieldBuilder);
                    ilGenerator.Emit(OpCodes.Ldarg_1);
                    ilGenerator.EmitCall(OpCodes.Call, combine.GetMethodInfo(), null);
                    ilGenerator.Emit(OpCodes.Castclass, ehType);
                    ilGenerator.Emit(OpCodes.Stfld, eventFieldBuilder);

                    // this.Subscribe(eventId, value);
                    Expression <Func <RuntimeProxy, object> > addEventHandler = o => o.Subscribe(null, null);
                    ilGenerator.Emit(OpCodes.Ldarg_0);
                    ilGenerator.Emit(OpCodes.Ldstr, eventInfo.Key);
                    ilGenerator.Emit(OpCodes.Ldarg_0);
                    ilGenerator.Emit(OpCodes.Ldfld, eventFieldBuilder);
                    ilGenerator.EmitCall(OpCodes.Callvirt, addEventHandler.GetMethodInfo(), null);
                    ilGenerator.Emit(OpCodes.Stloc_2);

                    ilGenerator.Emit(OpCodes.Ret);

                    typeBuilder.DefineMethodOverride(getMb, addMethodInfo);
                }
                // Implement event handler remove method
                // remove { ... }
                {
                    MethodInfo    removeMethodInfo = eventInfo.Value.GetRemoveMethod();
                    MethodBuilder getMb            = typeBuilder.DefineMethod(removeMethodInfo.Name, MethodAttributes.Public | MethodAttributes.Virtual, typeof(void), new Type[] { eventInfo.Value.EventHandlerType });
                    ILGenerator   ilGenerator      = getMb.GetILGenerator();

                    Type         ehType   = eventInfo.Value.EventHandlerType;
                    LocalBuilder typeLb   = ilGenerator.DeclareLocal(typeof(Type), true);
                    LocalBuilder objectLb = ilGenerator.DeclareLocal(typeof(object), true);
                    LocalBuilder retLb    = ilGenerator.DeclareLocal(typeof(bool), true);

                    // _event -= value;
                    Expression <Func <Delegate, object> > remove = d => Delegate.Remove(d, d);
                    ilGenerator.Emit(OpCodes.Ldarg_0);
                    ilGenerator.Emit(OpCodes.Ldarg_0);
                    ilGenerator.Emit(OpCodes.Ldfld, eventFieldBuilder);
                    ilGenerator.Emit(OpCodes.Ldarg_1);
                    ilGenerator.EmitCall(OpCodes.Call, remove.GetMethodInfo(), null);
                    ilGenerator.Emit(OpCodes.Castclass, ehType);
                    ilGenerator.Emit(OpCodes.Stfld, eventFieldBuilder);

                    // this.Unsubscribe(eventId, value);
                    Expression <Func <RuntimeProxy, object> > removeEventHandler = o => o.Unsubscribe(null, null);
                    ilGenerator.Emit(OpCodes.Ldarg_0);
                    ilGenerator.Emit(OpCodes.Ldstr, eventInfo.Key);
                    ilGenerator.Emit(OpCodes.Ldarg_0);
                    ilGenerator.Emit(OpCodes.Ldfld, eventFieldBuilder);
                    ilGenerator.EmitCall(OpCodes.Callvirt, removeEventHandler.GetMethodInfo(), null);
                    ilGenerator.Emit(OpCodes.Stloc_2);

                    ilGenerator.Emit(OpCodes.Ret);

                    typeBuilder.DefineMethodOverride(getMb, removeMethodInfo);
                }
            }

            // Implement properties
            foreach (var propertyInfo in ObjectDescriptor.GetProperties <T>())
            {
                Expression <Func <RuntimeTypeHandle, object> > getTypeFromHandle = t => Type.GetTypeFromHandle(t);
                PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyInfo.Value.Name, propertyInfo.Value.Attributes, propertyInfo.Value.PropertyType, null);

                if (propertyInfo.Value.CanRead)
                {
                    MethodInfo getMethodInfo = propertyInfo.Value.GetGetMethod();

                    MethodBuilder getMb       = typeBuilder.DefineMethod(getMethodInfo.Name, MethodAttributes.Public | MethodAttributes.Virtual, propertyInfo.Value.PropertyType, Type.EmptyTypes);
                    ILGenerator   ilGenerator = getMb.GetILGenerator();

                    LocalBuilder typeLb      = ilGenerator.DeclareLocal(typeof(Type), true);
                    LocalBuilder outObjectLb = ilGenerator.DeclareLocal(typeof(object), true);
                    LocalBuilder retLb       = ilGenerator.DeclareLocal(typeof(bool), true);

                    // obj = this.GetValue(propertyId, out result);
                    object obj = null;
                    Expression <Func <RuntimeProxy, object> > setValue = o => o.GetValue(null, out obj);
                    ilGenerator.Emit(OpCodes.Ldarg_0);
                    ilGenerator.Emit(OpCodes.Ldstr, propertyInfo.Key);
                    ilGenerator.Emit(OpCodes.Ldloca_S, 1);
                    ilGenerator.EmitCall(OpCodes.Callvirt, setValue.GetMethodInfo(), null);
                    ilGenerator.Emit(OpCodes.Stloc_2);

                    // Handle value return types
                    Expression <Func <object, object> > createInstance = a => Activator.CreateInstance(a.GetType());
                    ilGenerator.Emit(OpCodes.Ldloc_1);
                    if (propertyInfo.Value.PropertyType.IsValueType)
                    {
                        Label retisnull = ilGenerator.DefineLabel();
                        Label endofif   = ilGenerator.DefineLabel();

                        // Create instance if value is null
                        ilGenerator.Emit(OpCodes.Ldnull);
                        ilGenerator.Emit(OpCodes.Ceq);
                        ilGenerator.Emit(OpCodes.Brtrue_S, retisnull);
                        ilGenerator.Emit(OpCodes.Ldloc_1);
                        ilGenerator.Emit(OpCodes.Unbox_Any, propertyInfo.Value.PropertyType);
                        ilGenerator.Emit(OpCodes.Br_S, endofif);
                        ilGenerator.MarkLabel(retisnull);
                        ilGenerator.Emit(OpCodes.Ldtoken, propertyInfo.Value.PropertyType);
                        ilGenerator.EmitCall(OpCodes.Call, getTypeFromHandle.GetMethodInfo(), null);
                        ilGenerator.EmitCall(OpCodes.Call, createInstance.GetMethodInfo(), null);
                        ilGenerator.Emit(OpCodes.Unbox_Any, propertyInfo.Value.PropertyType);
                        ilGenerator.MarkLabel(endofif);
                    }

                    ilGenerator.Emit(OpCodes.Ret);

                    propertyBuilder.SetGetMethod(getMb);
                    typeBuilder.DefineMethodOverride(getMb, getMethodInfo);
                }

                if (propertyInfo.Value.CanWrite)
                {
                    MethodInfo    setMethodInfo = propertyInfo.Value.GetSetMethod();
                    MethodBuilder setMb         = typeBuilder.DefineMethod(setMethodInfo.Name, MethodAttributes.Public | MethodAttributes.Virtual, typeof(void), new Type[] { propertyInfo.Value.PropertyType });
                    ILGenerator   ilGenerator   = setMb.GetILGenerator();

                    LocalBuilder typeLb   = ilGenerator.DeclareLocal(typeof(Type), true);
                    LocalBuilder objectLb = ilGenerator.DeclareLocal(propertyInfo.Value.PropertyType, true);
                    LocalBuilder retLb    = ilGenerator.DeclareLocal(typeof(bool), true);

                    // this.SetValue(propertyId, value);
                    ilGenerator.Emit(OpCodes.Ldarg_1);
                    ilGenerator.Emit(OpCodes.Stloc_1);
                    Expression <Func <RuntimeProxy, object> > setValue = o => o.SetValue(null, null);
                    ilGenerator.Emit(OpCodes.Ldarg_0);
                    ilGenerator.Emit(OpCodes.Ldstr, propertyInfo.Key);
                    ilGenerator.Emit(OpCodes.Ldloc_1);
                    if (propertyInfo.Value.PropertyType.IsValueType)
                    {
                        ilGenerator.Emit(OpCodes.Box, propertyInfo.Value.PropertyType);
                    }
                    ilGenerator.EmitCall(OpCodes.Callvirt, setValue.GetMethodInfo(), null);
                    ilGenerator.Emit(OpCodes.Stloc_2);

                    ilGenerator.Emit(OpCodes.Ret);

                    propertyBuilder.SetSetMethod(setMb);
                    typeBuilder.DefineMethodOverride(setMb, setMethodInfo);
                }
            }

            // Implement methods
            foreach (var methodInfo in ObjectDescriptor.GetMethods <T>())
            {
                object obj = null;
                Expression <Func <RuntimeProxy, object> >      invoke            = o => o.Invoke(null, null, out obj);
                Expression <Func <object, object> >            createInstance    = a => Activator.CreateInstance(a.GetType());
                Expression <Func <RuntimeTypeHandle, object> > getTypeFromHandle = t => Type.GetTypeFromHandle(t);
                Expression <Func <List <object>, object> >     listToArray       = l => l.ToArray();
                Expression <Action <List <object> > >          listAdd           = l => l.Add(new object());
                var parameterInfoArray   = methodInfo.Value.GetParameters();
                var genericArgumentArray = methodInfo.Value.GetGenericArguments();

                MethodBuilder mb = typeBuilder.DefineMethod(methodInfo.Value.Name, MethodAttributes.Public | MethodAttributes.Virtual, methodInfo.Value.ReturnType, parameterInfoArray.Select(pi => pi.ParameterType).ToArray());
                if (genericArgumentArray.Any())
                {
                    mb.DefineGenericParameters(genericArgumentArray.Select(s => s.Name).ToArray());
                }

                ILGenerator  ilGenerator = mb.GetILGenerator();
                LocalBuilder typeLb      = ilGenerator.DeclareLocal(typeof(Type), true);
                LocalBuilder paramsLb    = ilGenerator.DeclareLocal(typeof(List <object>), true);
                LocalBuilder resultLb    = ilGenerator.DeclareLocal(typeof(object), true);
                LocalBuilder retLb       = ilGenerator.DeclareLocal(typeof(bool), true);

                // Create method argument array
                ilGenerator.Emit(OpCodes.Newobj, typeof(List <object>).GetConstructor(Type.EmptyTypes));
                ilGenerator.Emit(OpCodes.Stloc_1);
                int i = 0;
                foreach (ParameterInfo pi in methodInfo.Value.GetParameters())
                {
                    i++;
                    ilGenerator.Emit(OpCodes.Ldloc_1);
                    ilGenerator.Emit(OpCodes.Ldarg, i);
                    if (pi.ParameterType.IsValueType)
                    {
                        ilGenerator.Emit(OpCodes.Box, pi.ParameterType);
                    }
                    ilGenerator.EmitCall(OpCodes.Callvirt, listAdd.GetMethodInfo(), null);
                }

                // this.Invoke(methodId, args, out result);
                ilGenerator.Emit(OpCodes.Ldarg_0);
                ilGenerator.Emit(OpCodes.Ldstr, methodInfo.Key);
                ilGenerator.Emit(OpCodes.Ldloc_1);
                ilGenerator.EmitCall(OpCodes.Callvirt, listToArray.GetMethodInfo(), null);
                ilGenerator.Emit(OpCodes.Ldloca_S, 2);
                ilGenerator.EmitCall(OpCodes.Callvirt, invoke.GetMethodInfo(), null);
                ilGenerator.Emit(OpCodes.Stloc_3);

                if (methodInfo.Value.ReturnType != typeof(void))
                {
                    ilGenerator.Emit(OpCodes.Ldloc_2);

                    // Handle value return types
                    if (methodInfo.Value.ReturnType.IsValueType)
                    {
                        Label retisnull = ilGenerator.DefineLabel();
                        Label endofif   = ilGenerator.DefineLabel();

                        // Create instance if value is null
                        ilGenerator.Emit(OpCodes.Ldnull);
                        ilGenerator.Emit(OpCodes.Ceq);
                        ilGenerator.Emit(OpCodes.Brtrue_S, retisnull);
                        ilGenerator.Emit(OpCodes.Ldloc_2);
                        ilGenerator.Emit(OpCodes.Unbox_Any, methodInfo.Value.ReturnType);
                        ilGenerator.Emit(OpCodes.Br_S, endofif);
                        ilGenerator.MarkLabel(retisnull);
                        ilGenerator.Emit(OpCodes.Ldtoken, methodInfo.Value.ReturnType);
                        ilGenerator.EmitCall(OpCodes.Call, getTypeFromHandle.GetMethodInfo(), null);
                        ilGenerator.EmitCall(OpCodes.Call, createInstance.GetMethodInfo(), null);
                        ilGenerator.Emit(OpCodes.Unbox_Any, methodInfo.Value.ReturnType);
                        ilGenerator.MarkLabel(endofif);
                    }
                }

                ilGenerator.Emit(OpCodes.Ret);

                typeBuilder.DefineMethodOverride(mb, methodInfo.Value);
            }

            // Create and store new type instance
            Type type = typeBuilder.CreateType();

            _runtimeProxyTypes.Add(typeof(T), type);

            return((T)Activator.CreateInstance(type, objectId, client));
        }