11

我正在使用 Mono.Cecil 生成一个程序集,该程序集包含一个派生类,该类覆盖导入的基类中的特定方法。覆盖方法是“隐式”覆盖。问题是我无法弄清楚如何将其指定为覆盖。

我正在使用以下代码来创建覆盖方法。

    void CreateMethodOverride(TypeDefinition targetType,
        TypeDefinition baseClass, string methodName, MethodInfo methodInfo)
    {
        // locate the matching base class method, which may
        // reside in a different module
        MethodDefinition baseMethod = baseClass
            .Methods.First(method => method.Name.Equals(methodName));

        MethodDefinition newMethod = targetType.Copy(methodInfo);
        newMethod.Name = baseMethod.Name;
        newMethod.Attributes = baseMethod.Attributes;
        newMethod.ImplAttributes = baseMethod.ImplAttributes;
        newMethod.SemanticsAttributes = baseMethod.SemanticsAttributes;
        targetType.Methods.Add(newMethod);
    }

据我了解,隐式覆盖必须具有与继承方法相同的签名。使用上面的代码,当我在 Reflector 中查看生成的方法时,基类和派生类方法具有完全相同的签名,即“public virtual void f(int param)”。

我尝试删除显式的“虚拟”属性,但派生方法最终成为“public void f(int param)”。

如何让派生方法具有正确的“public override void f(int param)”签名?

注意:我有一个扩展方法(“TypeDefinition.Copy”),它克隆一个 MethodInfo 并通过导入所有引用的类型等返回一个 MethodDefinition。

4

2 回答 2

15

在您的基类中,假设您生成以下方法:

public virtual void f(int);

您必须确保它的标志IsVirtual设置为真。您还必须确保它具有标志IsNewSlot = true,以确保它在虚拟方法表中有一个新槽。

现在,对于被覆盖的方法,您要生成:

public override void f(int);

为此,您还需要将方法设为 be IsVirtual,但还要告诉它它不是新的虚拟方法,而是隐式覆盖另一个方法,因此您必须使用它.IsReuseSlot = true

而且因为您使用的是隐式覆盖,所以您还必须确保这两种方法都是.IsHideBySig = true.

有了这一切,你应该有一个适当的覆盖方法。

于 2011-11-12T09:24:49.060 回答
10

为了其他读者的利益,以下是按照 JB 的答案获得的最终结果:

void CreateMethodOverride(TypeDefinition targetType,
    TypeDefinition baseClass, string methodName, MethodInfo methodInfo)
{
    MethodDefinition baseMethod = baseClass
        .Methods.First(method => method.Name.Equals(methodName));

    MethodDefinition newMethod = targetType.Copy(methodInfo);
    newMethod.Name = baseMethod.Name;

    // Remove the 'NewSlot' attribute
    newMethod.Attributes = baseMethod.Attributes & ~MethodAttributes.NewSlot;

    // Add the 'ReuseSlot' attribute
    newMethod.Attributes |= MethodAttributes.ReuseSlot;

    newMethod.ImplAttributes = baseMethod.ImplAttributes;
    newMethod.SemanticsAttributes = baseMethod.SemanticsAttributes;
    targetType.Methods.Add(newMethod);
}
于 2011-11-12T20:36:38.997 回答