Question

I'm n00b in IL language. In my task i have to create dynamic types inherited from System.ServiceModel.DomainServices.Client.Entity. When i am adding additional code to set method of property, i receive "operation could destabilize the runtime". Help me, please, resolve that problem.

Code from Reflector:

L_0000: nop 
L_0001: ldarg.0 
L_0002: ldstr "Field"
L_0007: ldarg.1 
L_0008: call instance void [System.ServiceModel.DomainServices.Client]System.ServiceModel.DomainServices.Client.Entity::ValidateProperty(string, object)
L_000d: nop 
L_000e: ldarg.0 
L_000f: ldarg.1 
L_0010: stfld string SEC.Client.Views.Test::_field
L_0015: ldarg.0 
L_0016: ldstr "Field"
L_001b: call instance void [System.ServiceModel.DomainServices.Client]System.ServiceModel.DomainServices.Client.Entity::RaisePropertyChanged(string)
L_0020: nop 
L_0021: ret 

My code:

  // Generate a private field
        FieldBuilder field = typeBuilder.DefineField("_" + propertyName, type,
                                                     FieldAttributes.Private);
        // Generate a public property
        PropertyBuilder property =
            typeBuilder.DefineProperty(propertyName,
                                       PropertyAttributes.None,
                                       type,
                                       new Type[] { type });

        if(attributes != null)
        {
            foreach(var attribute in attributes)
            {
                property.SetCustomAttribute(attribute);
            }
        }

        // The property set and property get methods require a special set of attributes:

        MethodAttributes GetSetAttr =
            MethodAttributes.Public |
            MethodAttributes.HideBySig;

        // Define the "get" accessor method for current private field.
        MethodBuilder currGetPropMthdBldr =
            typeBuilder.DefineMethod("get_value",
                                     GetSetAttr,
                                     type,
                                     Type.EmptyTypes);

        // Intermediate Language stuff...
        ILGenerator currGetIL = currGetPropMthdBldr.GetILGenerator();
        currGetIL.Emit(OpCodes.Ldarg_0);
        currGetIL.Emit(OpCodes.Ldfld, field);
        currGetIL.Emit(OpCodes.Ret);

        // Define the "set" accessor method for current private field.
        MethodBuilder currSetPropMthdBldr =
            typeBuilder.DefineMethod("set_value",
                                     GetSetAttr,
                                     null,
                                     new Type[] { type });

        ILGenerator currSetIL = currSetPropMthdBldr.GetILGenerator();
        currSetIL.Emit(OpCodes.Nop);
        currSetIL.Emit(OpCodes.Ldarg_0);
        currSetIL.Emit(OpCodes.Ldstr, propertyName);
        currSetIL.Emit(OpCodes.Ldarg_1);
        var m = typeof(Entity).GetMethod("ValidateProperty",
                                         BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
                                         null, new [] {typeof(string), typeof(object)}, null);
        currSetIL.EmitCall(OpCodes.Call, m, null);
        currSetIL.Emit(OpCodes.Nop);
        currSetIL.Emit(OpCodes.Ldarg_0);
        currSetIL.Emit(OpCodes.Ldarg_1);
        currSetIL.Emit(OpCodes.Stfld, field);
        currSetIL.Emit(OpCodes.Ldarg_0);
        currSetIL.Emit(OpCodes.Ldstr, propertyName);
        m = typeof(Entity).GetMethod("RaisePropertyChanged",
                                        BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
        currSetIL.EmitCall(OpCodes.Call, m, null);
        currSetIL.Emit(OpCodes.Nop);
        currSetIL.Emit(OpCodes.Ret);

        // Last, we must map the two methods created above to our PropertyBuilder to
        // their corresponding behaviors, "get" and "set" respectively.
        property.SetGetMethod(currGetPropMthdBldr);
        property.SetSetMethod(currSetPropMthdBldr);
Was it helpful?

Solution 3

After adding box instruction, all is fine.

OTHER TIPS

Yes, it works if you add the box instruction:

currSetIL.Emit(OpCodes.Box, type);  

before:

currSetIL.EmitCall(OpCodes.Call, m, null);

This will take a list of strings and values/Types and make and object from it.

using System;


public class CreateObject
{
    public static object CreatePropertyObject(System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, object>> objData)
    {
        System.Collections.Generic.Dictionary<string, Type> list = new System.Collections.Generic.Dictionary<string, Type>();
        foreach (var o in objData)
        {
            list.Add(o.Key, o.Value.GetType());
        }

        Type newType = BuildPropertyObject(list);
        object newObject = NewPropertyObject(newType, objData);
        return newObject;
    }

    public static object NewPropertyObject(Type newType, System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, object>> objData)
    {
        var newObject = Activator.CreateInstance(newType);
        foreach (var item in objData)
        {
            // Set the value on the new object
            newObject.GetType().GetProperty(item.Key).SetValue(newObject, item.Value, null);
        }
        return newObject;
    }

    public static Type BuildPropertyObject(System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, Type>> obj)
    {
        string nameOfDLL = "magic.dll";
        string nameOfAssembly = "magic_Assembly";
        string nameOfModule = "magic_Module";
        string nameOfType = "magic_Type";

        System.Reflection.AssemblyName assemblyName = new System.Reflection.AssemblyName { Name = nameOfAssembly };
        System.Reflection.Emit.AssemblyBuilder assemblyBuilder = System.Threading.Thread.GetDomain().DefineDynamicAssembly(assemblyName, System.Reflection.Emit.AssemblyBuilderAccess.RunAndSave);
        System.Reflection.Emit.ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(nameOfModule, nameOfDLL);
        System.Reflection.Emit.TypeBuilder typeBuilder = moduleBuilder.DefineType(nameOfType, System.Reflection.TypeAttributes.Public | System.Reflection.TypeAttributes.Class);

        foreach (var prop in obj)
        {
            string Name = prop.Key;
            Type DataType = prop.Value;

            System.Reflection.Emit.FieldBuilder field = typeBuilder.DefineField("_" + Name, DataType, System.Reflection.FieldAttributes.Private);
            System.Reflection.Emit.PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(Name, System.Reflection.PropertyAttributes.SpecialName, DataType, null);
            System.Reflection.MethodAttributes methodAttributes = System.Reflection.MethodAttributes.Public | System.Reflection.MethodAttributes.HideBySig | System.Reflection.MethodAttributes.SpecialName;
            System.Reflection.Emit.MethodBuilder methodBuilderGetter = typeBuilder.DefineMethod("get_" + Name, methodAttributes, DataType, new Type[] { });
            System.Reflection.Emit.MethodBuilder methodBuilderSetter = typeBuilder.DefineMethod("set_" + Name, methodAttributes, typeof(void), new Type[] { DataType });

            System.Reflection.Emit.ILGenerator ilGeneratorGetter = methodBuilderGetter.GetILGenerator();
            ilGeneratorGetter.Emit(System.Reflection.Emit.OpCodes.Ldarg_0);
            ilGeneratorGetter.Emit(System.Reflection.Emit.OpCodes.Ldfld, field);
            ilGeneratorGetter.Emit(System.Reflection.Emit.OpCodes.Ret);


            System.Reflection.Emit.ILGenerator ilGeneratorSetter = methodBuilderSetter.GetILGenerator();
            ilGeneratorSetter.Emit(System.Reflection.Emit.OpCodes.Ldarg_0);
            ilGeneratorSetter.Emit(System.Reflection.Emit.OpCodes.Ldarg_1);
            ilGeneratorSetter.Emit(System.Reflection.Emit.OpCodes.Stfld, field);
            ilGeneratorSetter.Emit(System.Reflection.Emit.OpCodes.Ret);

            propertyBuilder.SetGetMethod(methodBuilderGetter);
            propertyBuilder.SetSetMethod(methodBuilderSetter);
        }

        // Yes! you must do this, it should not be needed but it is!
        Type dynamicType = typeBuilder.CreateType();

        // Save to file
        assemblyBuilder.Save(nameOfDLL);
        return dynamicType;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top