Ejemplo n.º 1
0
        private static void CreateMethodPrototypesDictionary(MethodDefinition method)
        {
            var prototypeType = method.DeclaringType.NestedTypes.Single(m => m.Name == "PrototypeClass");
            var delegateType = prototypeType.NestedTypes.Single(m => m.Name == "Callback_" + ComposeFullMethodName(method));
            var dicType = method.Module.Import(typeof(Dictionary<Type, object>));
            var dicConst = method.Module.Import(typeof(Dictionary<Type, object>).GetConstructor(Type.EmptyTypes));

            //Create the dictionary itself
            var protoDic = new FieldDefinition('_'+ComposeFullMethodName(method), FieldAttributes.Private, dicType);
            protoDic.DeclaringType = prototypeType;
            prototypeType.Fields.Add(protoDic);

            //Create property for the dictionary.
            var Property = new PropertyDefinition(ComposeFullMethodName(method), PropertyAttributes.None, dicType);
            var get = new MethodDefinition("get_" + Property.Name, MethodAttributes.Assembly | MethodAttributes.SpecialName | MethodAttributes.CompilerControlled | MethodAttributes.HideBySig, dicType);
            var set = new MethodDefinition("set_" + Property.Name, MethodAttributes.Assembly | MethodAttributes.SpecialName | MethodAttributes.CompilerControlled | MethodAttributes.HideBySig, method.Module.Import(typeof(void)));

            //IL getter
            //used to create the dictionary object if it's not initialized.
            get.Body.Variables.Add(new VariableDefinition(dicType));
            get.Body.Variables.Add(new VariableDefinition(method.Module.Import(typeof(bool))));

            get.Body.InitLocals = true;
            set.Body.InitLocals = true;

            ICollection<Instruction> jmpReplacements = new Collection<Instruction>();

            var il = get.Body.GetILProcessor();

            //check for dictionary existance
            il.Emit(OpCodes.Nop);
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldfld, protoDic.Instance()); // class [mscorlib]System.Collections.Generic.Dictionary`2<class [mscorlib]System.Type, object> valuetype Cheese.GenericStorage`1/Test<!T>::Dict
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Ceq);
            il.Emit(OpCodes.Ldc_I4_0);
            il.Emit(OpCodes.Ceq);
            il.Emit(OpCodes.Stloc_1);
            il.Emit(OpCodes.Ldloc_1);
            il.Emit(OpCodes.Brtrue_S, label("returnDict")); // IL_001e

            //create dictionary
            il.Emit(OpCodes.Nop);
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Newobj,dicConst); // instance void class [mscorlib]System.Collections.Generic.Dictionary`2<class [mscorlib]System.Type, object>::.ctor()
            il.Emit(OpCodes.Stfld, protoDic.Instance());  // class [mscorlib]System.Collections.Generic.Dictionary`2<class [mscorlib]System.Type, object> valuetype Cheese.GenericStorage`1/Test<!T>::Dict

            il.SetLabel("returnDict");

            //return dictionary reference
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldfld, protoDic.Instance()); // class [mscorlib]System.Collections.Generic.Dictionary`2<class [mscorlib]System.Type, object> valuetype Cheese.GenericStorage`1/Test<!T>::Dict
            il.Emit(OpCodes.Stloc_0);
            il.Emit(OpCodes.Ldloc_0);
            il.Emit(OpCodes.Ret);

            //IL setter
            set.Body.GetILProcessor().Emit(OpCodes.Ldarg_0);
            set.Body.GetILProcessor().Emit(OpCodes.Ldarg_1);
            set.Body.GetILProcessor().Emit(OpCodes.Stfld, protoDic.Instance());
            set.Body.GetILProcessor().Emit(OpCodes.Ret);

            Property.GetMethod = get;
            prototypeType.Methods.Add(get);

            set.Parameters.Add(new ParameterDefinition("value", ParameterAttributes.None, dicType));
            Property.SetMethod = set;
            prototypeType.Methods.Add(set);
            prototypeType.Properties.Add(Property);

            //Create set* method
            var setMethod = new MethodDefinition("Set" + ComposeFullMethodName(method),
                                                 MethodAttributes.Public | MethodAttributes.HideBySig,
                                                 method.Module.Import(typeof (void)));

            setMethod.ImportGenericParams(method);

            var dt = new GenericInstanceType(delegateType);
            foreach (var param in method.DeclaringType.GenericParameters.Concat(setMethod.GenericParameters))
                dt.GenericArguments.Add(param);

            setMethod.Parameters.Add(new ParameterDefinition("code", ParameterAttributes.None, dt));

            var systemTypeClass = method.Module.Import(typeof(Type));
            var TypeFromHandle = method.Module.Import(systemTypeClass.Resolve().Methods.Single(m => m.Name == "GetTypeFromHandle"));
            var dictProperty = prototypeType.Properties.Single(m => m.Name == ComposeFullMethodName(method));

            Type[] systemFuncs = { typeof(Func<>), typeof(Func<,>), typeof(Func<,,>), typeof(Func<,,,>), typeof(Func<,,,,>)};
            var systemFuncClass = method.Module.Import(systemFuncs[method.GenericParameters.Count-1]);
            systemFuncClass = new GenericInstanceType(systemFuncClass);
            foreach (var param in method.GenericParameters)
                ((GenericInstanceType)systemFuncClass).GenericArguments.Add(param);

            var dictType = method.Module.Import(typeof(Dictionary<Type, object>));
            var dictAddMethod = method.Module.Import(dictType.Resolve().Methods.Single(m => m.Name == "Add"));
            dictAddMethod.DeclaringType = dictType;

            il = setMethod.Body.GetILProcessor();

            il.Emit(OpCodes.Nop);
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Call, dictProperty.GetMethod.Instance()); // instance class [mscorlib]System.Collections.Generic.Dictionary`2<class [mscorlib]System.Type, object> valuetype Cheese.GenericStorage`1/Test<!T>::get_DictAccesor()
            il.Emit(OpCodes.Ldtoken, systemFuncClass); // class [System.Core]System.Func`2<!!L, !!H>
            il.Emit(OpCodes.Call, TypeFromHandle); // class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
            il.Emit(OpCodes.Ldarg_1);
            il.Emit(OpCodes.Callvirt,dictAddMethod); // instance void class [mscorlib]System.Collections.Generic.Dictionary`2<class [mscorlib]System.Type, object>::Add(!0, !1)
            il.Emit(OpCodes.Nop);
            il.Emit(OpCodes.Ret);

            prototypeType.Methods.Add(setMethod);
            setMethod.DeclaringType = prototypeType;
        }