IL发出断开连接的上下文错误

时间:2016-09-06 16:29:19

标签: c# reflection reflection.emit

我试图在IL发射中创建一个setter,但是这个setter只能接受非null的对象,否则就必须抛出异常。 这是我的类Notnull,它接收了一个il Generator和一个FieldBuilder,其中setter(如果不为null)必须存储它的值。

 public class NonNull 
{
    public void CreateIL(ILGenerator il, FieldBuilder field)
    {
        il.Emit(OpCodes.Ldarg_0);        // Push "this" on the stack

        il.Emit(OpCodes.Newobj, typeof(Utils).GetConstructor(new Type[] { }));
        il.Emit(OpCodes.Stloc_1);

        il.Emit(OpCodes.Ldarg_1);
        il.Emit(OpCodes.Stloc_2);

        il.Emit(OpCodes.Ldloc_2);
        il.Emit(OpCodes.Ldloc_1);        // Push "value" on the stack
        il.Emit(OpCodes.Callvirt,typeof(Utils).GetMethod("checkIfNull"));
        il.Emit(OpCodes.Pop);

        il.Emit(OpCodes.Ldloc_2);
        il.Emit(OpCodes.Stfld, field);   // Set the field "_Name" to "value"
        il.Emit(OpCodes.Ret);
    }
}

我在IL中调用的类工具并抛出我的异常。

class Utils
    {
        public void checkIfNull(object obj)
        {
            if (obj == null) throw new MyException();
        }
    }

当我尝试创建我的新类型(具有此IL)时,它会显示Disconnected context错误。

2 个答案:

答案 0 :(得分:1)

通过使用非静态方法,您正在变得比它需要的更复杂。如果不需要对象引用来调用该方法,则该方法应始终是静态的。

这基本上就是你现在想要发出的东西:

public string Name
{
    set
    {
        Utils u = new Utils();
        string s = value;
        u.checkIfNull(s);
        _Name = s;
    }
}

完全没有必要创建Utils类的实例来进行检查。

首先制作checkIfNull()静态:

static class Utils
{
    public static void checkIfNull(object obj)
    {
        if (obj == null) throw new MyException();
    }
}

这是你应该尝试发出的:

public string Name
{
    set
    {
        Utils.checkIfNull(value);
        _Name = value;
    }
}

以下是:

public class NonNull 
{
    public static void CreateIL(ILGenerator il, FieldBuilder field)
    {
        il.Emit(OpCodes.Ldarg_1); // Push "value" on the stack
        il.Emit(OpCodes.Call, typeof(Utils).GetMethod("checkIfNull"));
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldarg_1);
        il.Emit(OpCodes.Stfld, field);   // Set the field "_Name" to "value"
        il.Emit(OpCodes.Ret);
    }
}

答案 1 :(得分:0)

我并不完全理解你想要做什么(使用NotNull类和FieldBuilder),但是我可以向你展示你的setter属性需要什么IL(检查null和set字段)。

如果对你有用,那很好。如果没有,让我知道问题,我们将解决它。

首先让我们描述一下我们想要的东西。

  1. 创建Utils
  2. 加载value arg
  3. 致电checkIfNull
  4. 加载this
  5. 加载value
  6. 设置字段
  7. 惩戒
  8. 发射将是这样的:

    il.Emit(OpCodes.Newobj, typeof(Utils).GetConstructor(new Type[] { }));
    il.Emit(OpCodes.Ldarg_1);
    il.Emit(OpCodes.Callvirt,typeof(Utils).GetMethod("checkIfNull"));
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Ldarg_1);
    il.Emit(OpCodes.Stfld, field);
    il.Emit(OpCodes.Ret);
    

    结果需要看起来像这样:

    newobj instance void MyApplication.Utils::.ctor() //create `Utils` object
    ldarg.1                                           //load `value`
    callvirt instance void 
             MyApplication.Utils::checkIfNull(object) //call checkForNull
    ldarg.0                                           //load `this`
    ldarg.1                                           //load `value`
    stfld int32 MyApplication.Program::_field         //store `value` in `_field`
    ret