使用反射查找枚举器的方法

3

背景:

我正在使用Harmony库修改现有代码。现有的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
2个回答

4

MoveNextIEnumerator<T> 上未定义,但在非泛型的 IEnumerator 上定义,后者被 IEnumerator<T> 继承。

接口继承与反射结合使用有些奇怪,因此您需要直接从定义该方法的基础接口获取方法信息:

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

你是不是想写 MethodInfo targetMethod = typeof(IEnumerator<>).GetMethod("MoveNext");?按照你的写法,会报错:Using the generic type 'IEnumerator<T>' requires 1 type arguments。但是,如果我按照我的方式写,它仍然会返回 null。 - Aze
@Aze 你试过从这个答案中复制/粘贴代码吗?kalimag明确地提到了非泛型IEnumerator。 - Sir Rufo
@SirRufo 哦,我现在意识到IEnumerator需要using System.Collections。谢谢。 - Aze
@Aze 查看文档总是一个明智的选择;o) - Sir Rufo
@Aze 个人而言,我非常喜欢 VS 中的 IntelliSenseExtender 扩展插件。[https://github.com/Dreamescaper/IntelliSenseExtender] - Sir Rufo

1
使用免费的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 }; }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接