EmitCall raises “operation could destabilize the runtime” in Silverlight
-
29-09-2019 - |
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);
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