2014-09-29 3 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) 

я получить правильный результат.

Где в коде может быть ошибка?

Любой, кто пытается помочь заблаговременно.

Вот Shortener пример, чтобы объяснить ошибку:

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'? В принципе, я думаю, что это полностью неопровержимо в текущем состоянии. –

+0

Я скорее подозреваю, что если вы запустите это через [Sigil] (https://www.nuget.org/packages/Sigil/), вы получите более полезное сообщение об ошибке –

+0

code 'for (var i = 0; i <_dims.Length; i ++) {...} 'отлично работает. Когда метод получает 1,2,3 в качестве параметров, этот цикл подталкивает 2568 в стек.Я пытаюсь использовать его в качестве параметра для делегирования метода «_read». нужно больше объяснений? –

ответ

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.

0 Однако, скорее всего, было бы эффективнее всего забыть про _read, а вместо этого сохранить viewAccessor, а call-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' были выбраны случайным образом, только для запуска примера предыдущей ошибки. –