【问题标题】:Using reflection to find an enumerator's method使用反射查找枚举器的方法
【发布时间】:2019-11-16 04:27:46
【问题描述】:

背景:

我正在使用Harmony Library 修改现有代码。现有的 C# 代码遵循以下结构:

public class ToModify
{
    public override void Update()
    {
        foreach (StatusItemGroup.Entry entry in collection)
        {
            // I am trying to alter an operation at the end of this loop.
        }
    }
}

public class StatusItemGroup
{
    public IEnumerator<Entry> GetEnumerator()
    {
        return items.GetEnumerator();
    }

    private List<Entry> items = new List<Entry>();

    public struct Entry { }
}

由于这种情况,我必须修改正在生成的 IL 代码,为此我必须获取目标操作数的MethodInfo。这是目标:

IL_12B6: callvirt  instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()

问题:

如何获取枚举器的MoveNext 方法的MethodInfo

我的尝试:

我能想到的一切都产生了null 的结果。这是我最基本的尝试:

MethodInfo targetMethod = typeof(IEnumerator<StatusItemGroup.Entry>).GetMethod("MoveNext");

我不明白为什么这不起作用,我不知道我需要做什么才能正确获得MethodInfo

【问题讨论】:

    标签: c# reflection cil enumerator ienumerator


    【解决方案1】:

    MoveNext 不是在IEnumerator&lt;T&gt; 上定义的,而是在由IEnumerator&lt;T&gt; 继承的非泛型IEnumerator 上定义的。

    接口继承与反射结合起来有点奇怪,所以你需要直接从定义它的基接口获取方法信息:

    MethodInfo targetMethod = typeof(System.Collections.IEnumerator).GetMethod("MoveNext");
    

    【讨论】:

    • 您的意思是MethodInfo targetMethod = typeof(IEnumerator&lt;&gt;).GetMethod("MoveNext");?正如您所写,我收到以下错误:Using the generic type 'IEnumerator&lt;T&gt;' requires 1 type arguments。但是,正如我所写,它仍然返回 null。
    • @Aze 您是否尝试复制/粘贴此答案中的代码? kalimag 明确提到了 non-generic IEnumerator
    • @SirRufo 啊,我现在意识到IEnumerator 需要using System.Collections。谢谢。
    • @Aze 查看文档总是一个明智的选择;o)
    • @Aze 我个人喜欢 VS 中的 IntelliSenseExtender 扩展
    【解决方案2】:

    使用免费的 LinqPad,我使用 Harmony 2.0 RC2 创建了这个。如您所见,我是否使用传递后缀来更改枚举器并将其包装起来。还有其他方法,我怀疑您实际上在某个地方有一个 IEnumeration。通过直接在返回 IEnumeration 的原始方法上使用传递后缀,这将更容易修补。在这种情况下不需要包装枚举器。

    但我不知道你的完整用例,所以现在,这是一个有效的例子:

    void Main()
    {
        var harmony = new Harmony("test");
        harmony.PatchAll();
    
        var group = new StatusItemGroup();
        var items = new List<StatusItemGroup.Entry>() { StatusItemGroup.Entry.Make("A"), StatusItemGroup.Entry.Make("B") };
        Traverse.Create(group).Field("items").SetValue(items);
    
        var enumerator = group.GetEnumerator();
        while(enumerator.MoveNext())
            Console.WriteLine(enumerator.Current.id);
    }
    
    [HarmonyPatch]
    class Patch
    {
        public class ProxyEnumerator<T> : IEnumerable<T>
        {
            public IEnumerator<T> enumerator;
            public Func<T, T> transformer;
            IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
            public IEnumerator<T> GetEnumerator()
            {
                while(enumerator.MoveNext())
                    yield return transformer(enumerator.Current);
            }
        } 
    
        [HarmonyPatch(typeof(StatusItemGroup), "GetEnumerator")]
        static IEnumerator<StatusItemGroup.Entry> Postfix(IEnumerator<StatusItemGroup.Entry> enumerator)
        {
            StatusItemGroup.Entry Transform(StatusItemGroup.Entry entry)
            {
                entry.id += "+";
                return entry;
            }
    
            var myEnumerator = new ProxyEnumerator<StatusItemGroup.Entry>()
            {
                enumerator = enumerator,
                transformer = Transform
            };
            return myEnumerator.GetEnumerator();
        }
    }
    
    public class StatusItemGroup
    {
        public IEnumerator<Entry> GetEnumerator()
        {
            return items.GetEnumerator();
        }
    
        private List<Entry> items = new List<Entry>();
    
        public struct Entry
        {
            public string id;
            public static Entry Make(string id) { return new Entry() { id = id }; }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-13
      • 1970-01-01
      • 1970-01-01
      • 2013-09-23
      • 2014-07-17
      相关资源
      最近更新 更多