使用Reflection确定C#方法是否具有关键字“覆盖”

时间:2011-04-21 15:42:40

标签: c# reflection override keyword

我原本希望能够轻松找到这个问题的答案,但我没有。 我想知道是否有可能确定某个方法是否将关键字“覆盖”归因于它,因为它的实例为MethodInfo

我在考虑以下可能会达到这个目的:

/// <summary> Returns whether the specified methodInfo is attributed with the keyword 'override'. </summary>
public static bool IsOverriding(this MethodInfo methodInfo)
{
    if (methodInfo == null) throw new ArgumentNullException();
    return methodInfo.DeclaringType != methodInfo.GetBaseDefinition().DeclaringType;
}

我已成功测试了一些非虚拟,虚拟和抽象的例子,但我觉得我错过了一些场景,可能是隐藏或泛型(虽然我无法弄清楚它会如何发挥作用)。

3 个答案:

答案 0 :(得分:2)

我也尝试找到这个东西。从问题的角度出发,您可以让IsOverridingoverride关键字工作。但是,为了隐藏,我尝试为关键字IsHiding创建new。这是基本的C#OOP:

  • override仅在基础方法包含abstractvirtual修饰符时使用。
  • new用于隐藏基于方法但名称相同但......
  • new无法应用于abstract基本方法,因为它会生成编译器错误。
  • 然而,如果基本方法包含new,则有趣的部分virtual也可以应用于方法。

不感兴趣的部分是我们可以隐藏或覆盖virtual方法。我们知道GetBaseDefinition()如果我们MethodInfo override方法,则会返回基数virtual。但区分它的关键是如果我们隐藏GetBaseDefinition()方法,MethodInfo将返回相同的MethodInfo而不是基础virtual

override关键字是必须的,而new仅用于取消警告消息。因此,我们可以通过overridenewIsAbstractIsVirtual的结合来区分DeclaringTypeBaseType

    public static bool IsOverriding(this MethodInfo methodInfo)
    {
        if (methodInfo == null) throw new ArgumentNullException("methodInfo");
        return methodInfo.DeclaringType != methodInfo.GetBaseDefinition().DeclaringType;
    }

    public static bool IsHiding(this MethodInfo methodInfo)
    {
        if (methodInfo == null) throw new ArgumentNullException("methodInfo");
        if (methodInfo.DeclaringType == methodInfo.GetBaseDefinition().DeclaringType)
        {
            var baseType = methodInfo.DeclaringType.BaseType;
            if (baseType != null)
            {
                MethodInfo hiddenBaseMethodInfo = null;
                var methods = baseType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Static);
                foreach (var mi in methods)
                    if (mi.Name == methodInfo.Name)
                    {
                        var miParams = mi.GetParameters();
                        var methodInfoParams = methodInfo.GetParameters();
                        if (miParams.Length == methodInfoParams.Length)
                        {
                            var i = 0;
                            for (; i < miParams.Length; i++)
                            {
                                if (miParams[i].ParameterType != methodInfoParams[i].ParameterType
                                    || ((miParams[i].Attributes ^ methodInfoParams[i].Attributes).HasFlag(ParameterAttributes.Out))) break;

                                // Simplified from:
                                //if (miParams[i].ParameterType != methodInfoParams[i].ParameterType
                                //    || (miParams[i].Attributes.HasFlag(ParameterAttributes.Out) && !methodInfoParams[i].Attributes.HasFlag(ParameterAttributes.Out))
                                //    || !(miParams[i].Attributes.HasFlag(ParameterAttributes.Out) && methodInfoParams[i].Attributes.HasFlag(ParameterAttributes.Out))) break;
                            }
                            if (i == miParams.Length)
                            {
                                hiddenBaseMethodInfo = mi;
                                break;
                            }
                        }
                    }
                if (hiddenBaseMethodInfo != null && !hiddenBaseMethodInfo.IsPrivate) return true;
            }
        }
        return false;
    }

我使用简单的继承测试它,它的工作原理。我不考虑通用方法..但是..


编辑:我只是更改上面的代码,因为我忘记了有关继承类型的想法可以包含新声明的方法,该方法不应该作为新方法。 IsHiding()首先会确保它具有相同的DeclaringType(看起来像是新的),但如果存在具有相同名称的方法,则需要查看DeclaringType.BaseType的基本声明类型。

请注意,由于没有BindingFlags.DeclaredOnlyGetMethod()将搜索整个基类型,因此无需递归搜索每种基类型。 BindingFlags.FlattenHierarchy用于在抽象抽象基类中包含静态方法,如下所示:

public abstract class A
{
    public static void Stat() { }
}
public abstract class B : A
{
}
public class C: B
{
    public new static void Stat() { }
}

编辑:我只修复上面的IsHiding()以检查基本方法重载,并使用AmbiguousMatchException来阻止GetMethods() GetMethod()。测试的重载与不同参数组合使用,与refoutparams和可选参数混合使用。根据参数计数,参数类型及其修饰符比较过载的签名:

    签名中包含
  • refout,但两者不能相互重载。
  • 返回类型,可选(默认值)和最右侧参数params应忽略

refParameterType本身进行比较(请参阅调试期间的“&amp;”结尾),而IsByRefout进行比较时无需进行比较。 Attributes标志。我正在使用简化表达式按位XOR来跳过循环,当且仅当其中一个属性具有标记Out时才会使标记不同。不要与.NET 4中的HasFlag混淆,它只是希望通过XOR结果确保Out位为1。

答案 1 :(得分:0)

你可以试试这个

public static bool IsOverriding(this MethodInfo methodInfo)
{
    if (methodInfo == null) throw new ArgumentNullException();
    return methodInfo.GetBaseDefinition() != methodInfo;
}

答案 2 :(得分:0)

好吧,我不知道会如何发挥作用。那里的代码确实确定了方法是定义还是重写。

在隐藏的情况下,声明类型是通过new隐藏方法的类型。 在泛型的情况下,所有方法都由模板类定义。