2014-09-29 57 views
2

我加入的ILGenerator串System.ObjectDisposedException在ILGenerated方法

ilGen.Emit(OpCodes.Ldarg_0); 
ilGen.Emit(OpCodes.Ldfld, readField); 

ilGen.Emit(OpCodes.Call, _read.GetMethodInfo()); 

到基本代码

private ReadItemDelegate _read; 

    /// <summary> 
    /// Init Get method of instance 
    /// </summary> 
    private void InitGetMethod() 
    { 
     var ti = typeof (int); 
     Type[] methodArgs2 = { _globalType, ti, ti, ti, ti, ti, ti, ti, ti, ti, ti };// 10 elements 

     #region this.Get = double(int, .., int) { return _shift0[i0] + .. + _shiftn[in] } 
     var dynamicMethod = new DynamicMethod("", ChildrenType, methodArgs2, _globalType);// create dynmic method 

     var ilGen = dynamicMethod.GetILGenerator(); 
     var fiShift = new FieldInfo[_dims.Length]; 

     for (var i = 0; i < _dims.Length; i++) // get links to all shift arrays 
     { 
      fiShift[i] = _globalType.GetField("_shift" + i, BindingFlags.NonPublic | BindingFlags.Instance); 
     } 

     var ldargs = new[] {OpCodes.Ldarg_1, OpCodes.Ldarg_2, OpCodes.Ldarg_3}; 

     var readField = _globalType.GetField("_read", BindingFlags.NonPublic | BindingFlags.Instance); 
     if (readField == null) throw new ArgumentNullException("_read"); 

     ilGen.Emit(OpCodes.Ldarg_0); 
     ilGen.Emit(OpCodes.Ldfld, readField); 

     for (var i = 0; i < _dims.Length; i++) 
     { 

      ilGen.Emit(OpCodes.Ldarg_0); //push link to class member 
      ilGen.Emit(OpCodes.Ldfld, fiShift[i]); //push link to shift array 
      if (i < 3) // push next param 
       ilGen.Emit(ldargs[i]); 
      else 
       ilGen.Emit(OpCodes.Ldarg_S, i+1); 

      ilGen.Emit(OpCodes.Ldelem_I8); // pop 3 vars and push value from our array by param as index. Result as I8 

      if (i>0) ilGen.Emit(OpCodes.Add); // pop 2 vars, summ and push back 

     } 

     ilGen.Emit(OpCodes.Call, _read.GetMethodInfo()); 

     ilGen.Emit(OpCodes.Ret); 

     Get = (GetItemDelegate) dynamicMethod.CreateDelegate(typeof(GetItemDelegate), this); // save method as Get variable 
     #endregion 
    } 

当我尝试使用

this.Get(1,2,3) 

我得到这个错误,但是当我使用

this._read(2568) 

我得到正确的结果。

代码在哪里可以是一个错误?

任何人谁试图帮助在此先感谢。

这里是缩短服务的例子来解释的错误:

using System; 
using System.Collections.Generic; 
using System.IO.MemoryMappedFiles; 
using System.Linq; 
using System.Reflection; 
using System.Reflection.Emit; 
using System.Text; 
using System.Threading.Tasks; 

namespace ConsoleApplication1 
{ 

    public class test 
    { 

     public delegate double GetItemDelegate(int i0 = 0, int i1 = 0, int i2 = 0); 
     public delegate double ReadItemDelegate(Int64 offset); 


     Type _globalType = typeof(test); 
     Type ChildrenType = typeof(double); 

     public GetItemDelegate Get; 
     private ReadItemDelegate _read; 

     public test() 
     { 
      var file = MemoryMappedFile.CreateOrOpen("file", 123); 
      var readMethod = typeof(MemoryMappedViewAccessor).GetMethod("ReadDouble"); 
      var viewAccessor = file.CreateViewAccessor(0, 123); 
      _read = (ReadItemDelegate)Delegate.CreateDelegate(typeof(ReadItemDelegate), viewAccessor, readMethod); 


      var ti = typeof(int); 
      Type[] methodArgs2 = { _globalType, ti, ti, ti };// 10 elements 

      var dynamicMethod = new DynamicMethod("", ChildrenType, methodArgs2, _globalType);// create dynmic method 
      var ilGen = dynamicMethod.GetILGenerator(); 


      var readField = _globalType.GetField("_read", BindingFlags.NonPublic | BindingFlags.Instance); 

      ilGen.Emit(OpCodes.Ldarg_0); 
      ilGen.Emit(OpCodes.Ldfld, readField); 

      ilGen.Emit(OpCodes.Ldc_I4, 3214); 
      ilGen.Emit(OpCodes.Conv_I8); 

      ilGen.Emit(OpCodes.Call, _read.GetMethodInfo()); 

      ilGen.Emit(OpCodes.Ret); 

      Get = (GetItemDelegate)dynamicMethod.CreateDelegate(typeof(GetItemDelegate), this); // save method as Get variable 
     } 
    } 
    class Program 
    { 

     static void Main(string[] args) 
     { 
      var tmp = new test(); 

      Console.WriteLine(tmp.Get()); 

      Console.ReadLine(); 
     } 

    } 
} 
+1

'this.Get(1,2,3)'和'this._read(2568)'之间的关系是什么?这是生成的方法? “GetItemDelegate”是什么样的?基本上来说:我们如何重现这一点?该方法如何有10个参数,但你的两个例子:不?什么是_dims,它有多大?什么是_shift字段?基本上,我认为在目前的状态下它完全无法回答。 – 2014-09-29 14:18:39

+0

我也有些怀疑,但是,如果你通过[印记](https://www.nuget.org/packages/Sigil/)运行它,你会得到一个更有用的错误信息 – 2014-09-29 14:28:09

+0

代码为'(VAR我= 0;我<_dims.Length;我++){...}'工作正常。当方法得到1,2,3作为参数时,这个循环将2568堆栈压入。我尝试使用它作为委托方法“_read”的参数。需要更多的解释吗? – 2014-09-29 16:08:58

回答

0

随着编辑的例子:这个问题是一个不正确的字段访问和方法调用一样简单;看看这里:

ilGen.Emit(OpCodes.Ldarg_0); 
ilGen.Emit(OpCodes.Ldfld, readField); 

ilGen.Emit(OpCodes.Ldc_I4, 3214); 
ilGen.Emit(OpCodes.Conv_I8); 

ilGen.Emit(OpCodes.Call, _read.GetMethodInfo()); 
ilGen.Emit(OpCodes.Ret); 

这里,_read是授人以viewAccessor.ReadDouble - 即ReadDouble是实例方法,并且viewAccessor是目标实例。我们有两个选择:

  • 的invoke ReadDouble反对比如我们以前存储在viewAccessor
  • 在委托调用Invoke

其中第二个我们可以通过像这样做:

// removed: ilGen.Emit(OpCodes.Call, _read.GetMethodInfo()); 
ilGen.Emit(OpCodes.Callvirt, _read.GetType().GetMethod("Invoke")); 
ilGen.Emit(OpCodes.Ret); 

请注意,您必须使用其它的值大于3214,或改变的容量/尺寸文件/视图访问到的东西比123更大。

但是,忘记_read并改为存储viewAccessor或调用virt-readMethod可能会更有效。例如:

private MemoryMappedViewAccessor _acc; 

// ... 

var viewAccessor = file.CreateViewAccessor(0, 123 * 1000); 
_acc = viewAccessor; 
var accField = _globalType.GetField("_acc", 
    BindingFlags.NonPublic | BindingFlags.Instance); 

// ... 

ilGen.Emit(OpCodes.Ldarg_0); 
ilGen.Emit(OpCodes.Ldfld, accField); 

ilGen.Emit(OpCodes.Ldc_I4, 3214); 
ilGen.Emit(OpCodes.Conv_I8); 

ilGen.Emit(OpCodes.Callvirt, readMethod); 
ilGen.Emit(OpCodes.Ret); 
+0

谢谢,它工作。数字'123'和'3214'是随机选择的,仅用于运行前一个错误的示例。 – 2014-09-30 05:28:17