确定 C# 方法是否具有关键字“override”使用反射

发布于 2024-11-02 14:14:45 字数 550 浏览 2 评论 0原文

我原以为这个问题能轻松找到答案,但我没有。 我想知道是否可以根据给定的 MethodInfo 实例来确定某个方法是否具有关键字“override”。

我在想也许以下内容可以实现这一点:

/// <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;
}

我已经成功测试了一些非虚拟、虚拟和抽象的示例,但我觉得我错过了一些场景,可能是隐藏或泛型(尽管我不知道如何这将会发挥作用)。

I had expected to find an answer easily to this problem, but I didn't.
I'd like to know if it is possible to determine whether a method has the keyword 'override' attributed to it, given its instance of MethodInfo.

I was thinking maybe the following would achieve that:

/// <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;
}

I've sucessfully tested some non-virtual, virtual and abstract examples, but I feel like I'm missing some scenarios, maybe with hiding or generics(although I can't figure out how that would come into play).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

段念尘 2024-11-09 14:14:45

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

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

插入的部分是我们可以隐藏或重写virtual方法。我们知道,如果我们覆盖一个虚拟方法,GetBaseDefinition()将返回基本的MethodInfo。但区分它的关键是,如果我们隐藏 virtual<,GetBaseDefinition() 将返回相同的 MethodInfo 而不是基本 MethodInfo /代码> 方法。

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

    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() 修复为使用 GetMethods() 而不是 GetMethod() 检查基本方法重载并防止 AmbigouslyMatchException。重载经过测试可与不同参数组合使用,与 refoutparams 和可选参数混合使用。根据参数计数、参数类型及其修饰符进行比较的重载签名:

  • 签名中包含 refout,但两者不能互相重载。
  • 应忽略

返回类型、可选(默认值)和最右边参数的 paramsParameterType 本身相比, ref(请参阅结尾的 '& ;' 在调试期间)并且不需要通过 IsByRef 进行比较,而 out 通过 Attributes 标志进行比较。当且仅当其中一个属性具有使签名不同的标志 Out 时,我使用简化表达式按位 XOR 来跳过循环。不要与.NET 4中的HasFlag混淆,它只是想通过XOR结果确保Out位为1。

I try to find this thing also. From the question, you give the idea to get IsOverriding work for override keyword. However for hiding I try to create IsHiding for keyword new. Here is the basic C# OOP:

  • override only used when the based method contain abstract or virtual modifier.
  • new is used to hide based method with the same name but...
  • new cannot be apply to abstract base method because it generate compiler error.
  • However the interesting part is new also can be applied to method if the base method contain virtual.

The inseresting part is we can hide or override virtual method. We know that GetBaseDefinition() will return the base MethodInfo if we override a virtual method. but the key to differentiate it is the GetBaseDefinition() will return the same MethodInfo instead of it base MethodInfo if we hiding virtual method.

override keyword is a must while new is only used to suppress the warning message. So we can diffrentiate override and new by the IsAbstract and IsVirtual combine with DeclaringType and BaseType.

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

I test it using the simple inheritance and it works. I don't think about generic method..yet..


EDIT: I just change the code above because I forgot the idea about inherited type can contain newly declared method which is should not threated as new. IsHiding() will first make sure it have the same DeclaringType (it seems like new) but need to look at the base declaring types by DeclaringType.BaseType if a method with the same name exist.

Note that because of there is no BindingFlags.DeclaredOnly, GetMethod() will search through the entire base types, so no need to recursively search to each base types. BindingFlags.FlattenHierarchy is used to include static method in abstract-abstract base class like this:

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

EDIT: I just fix the IsHiding() above to check for base method overloads and prevent AmbiguousMatchException by using GetMethods() instead of GetMethod(). The overloads tested to work with combination with different parameters, mix with ref, out, params and optional parameter. Signature for overloads being compared based on parameter count, parameter types and its modifier:

  • ref or out included in the signature but both cannot be overloaded to each other.
  • return type, optional (default value) and params on right most parameter should be ignored

ref compared by the ParameterType itself (see the ending '&' during debugging) and no need to compare by the IsByRef while the out compared by the Attributes flag. I am using simplified expression bitwise XOR to skip the loop if and only if one of the attributes has flag Out which makes the signature different. Don't confused with HasFlag in .NET 4, it just want to make sure Out bit is 1 by the XOR result.

世界和平 2024-11-09 14:14:45

好吧,我也不明白这会如何发挥作用。您的代码确实确定了是否定义或重写了方法。

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

Well, I don't see how that would come into play either. Your code there does indeed determine whether a method is defined or overriden.

In the case of hiding, the declaring type is the one that hides the method via new.
In the case of generics, all methods are defined by the template class.

口干舌燥 2024-11-09 14:14:45

你可以试试这个

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

You can try this

public static bool IsOverriding(this MethodInfo methodInfo)
{
    if (methodInfo == null) throw new ArgumentNullException();
    return methodInfo.GetBaseDefinition() != methodInfo;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文