我正在尝试创建一个从属性setter创建委托

时间:2013-11-25 23:19:01

标签: c# .net il

我正在尝试在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代码尝试避免转换,如旧代码中所示。我试图避免转换,因为此代码需要尽可能快。

1 个答案:

答案 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);