【问题标题】:System.ObjectDisposedException in ILGenerated methodILGenerated 方法中的 System.ObjectDisposedException
【发布时间】:2014-09-29 14:14:56
【问题描述】:

我添加到 ILGenerator 字符串

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();
        }

    }
}

【问题讨论】:

  • this.Get(1,2,3)this._read(2568)是什么关系?生成的方法是什么? GetItemDelegate 是什么样的?基本上:我们如何重现这个?该方法为什么有10个参数,但是您的两个示例:没有?什么是_dims,它有多大? _shift 字段是什么?基本上,我认为在目前的状态下是完全无法回答的。
  • 不过,我相当怀疑,如果您通过 Sigil 运行此程序,您会收到更有用的错误消息
  • 代码for (var i = 0; i &lt; _dims.Length; i++) {...} 工作正常。当方法获取 1,2,3 作为参数时,此循环将 2568 推入堆栈。我尝试将其用作委托方法“_read”的参数。需要更多解释吗?
  • 是的....你看到我问的所有问题了吗?基本上:您应该尝试将其简化为一个可重现的示例,这里的人们可以实际运行来查看问题。这样做很有可能:你会发现问题;但如果你不这样做,这里的人(比如我自己)很有可能会这样做。
  • 好的,我会尝试获得可重现的示例。

标签: c# dynamic reflection delegates opcode


【解决方案1】:

对于编辑中的示例:问题很简单,就像不正确的字段访问和方法调用一样;看这里:

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

这里,_readviewAccessor.ReadDouble 的委托 - 即 ReadDouble 是实例方法,viewAccessor 是目标实例。我们有两种选择:

  • 针对我们之前存储在viewAccessor 中的实例调用ReadDouble
  • 在委托上调用 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);

【讨论】:

  • 谢谢,它成功了。数字1233214 是随机选择的,仅用于运行上一个错误的示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-08
  • 2020-12-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-23
相关资源
最近更新 更多