我正在尝试在il代码中创建属性setter委托。当前代码适用于字符串,但对于int,bool,datetime(所有值类型),我得到“操作可能会破坏运行时的稳定性”。
DynamicMethod method = new DynamicMethod( "Setter", typeof ( void ), new[]
{
typeof ( T ), typeof ( Object )
}, true );
var ilgen = method.GetILGenerator();
ilgen.Emit( OpCodes.Ldarg,0 );
ilgen.Emit( OpCodes.Castclass, property.DeclaringType );
ilgen.Emit( OpCodes.Ldarg,1 );
ilgen.Emit(OpCodes.Unbox_Any, property.PropertyType);
ilgen.Emit( OpCodes.Box,property.PropertyType );
ilgen.Emit( OpCodes.Call, property.GetSetMethod() );
ilgen.Emit( OpCodes.Ret );
var action = method.CreateDelegate( typeof ( Action<T, Object> ) ) as Action<T, Object>;
return action;
//var target = Expression.Parameter(typeof(T), "obj");
//var value = Expression.Parameter(typeof(Object), "value");
//var body = Expression.Assign(
// Expression.Property(Expression.Convert(target, property.DeclaringType), property),
// Expression.Convert(value, property.PropertyType));
//var lambda = Expression.Lambda<Action<T, Object>>(body, target, value);
//return lambda.Compile();
我已经使用了unbox和box来尝试获取int工作这两行也可以是一个castclass,字符串可以工作,但仍然会得到与值类型相同的错误。
我正在使用il代码尝试避免转换,如旧代码中所示。我试图避免转换,因为此代码需要尽可能快。
答案 0 :(得分:1)
您知道属性的类型,因此您只需生成适当的代码即可。如果它是一个引用类型,那么你必须进行转换,如果它是一个值类型,那么你必须取消装箱。这很有效:
ilgen.Emit(OpCodes.Ldarg, 1);
if (property.PropertyType.IsValueType)
ilgen.Emit(OpCodes.Unbox_Any, property.PropertyType);
else ilgen.Emit(OpCodes.Castclass, property.PropertyType);