我原本希望能够轻松找到这个问题的答案,但我没有。
我想知道是否有可能确定某个方法是否将关键字“覆盖”归因于它,因为它的实例为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;
}
我已成功测试了一些非虚拟,虚拟和抽象的例子,但我觉得我错过了一些场景,可能是隐藏或泛型(虽然我无法弄清楚它会如何发挥作用)。
答案 0 :(得分:2)
我也尝试找到这个东西。从问题的角度出发,您可以让IsOverriding
为override
关键字工作。但是,为了隐藏,我尝试为关键字IsHiding
创建new
。这是基本的C#OOP:
override
仅在基础方法包含abstract
或virtual
修饰符时使用。new
用于隐藏基于方法但名称相同但...... new
无法应用于abstract
基本方法,因为它会生成编译器错误。new
,则有趣的部分virtual
也可以应用于方法。不感兴趣的部分是我们可以隐藏或覆盖virtual
方法。我们知道GetBaseDefinition()
如果我们MethodInfo
override
方法,则会返回基数virtual
。但区分它的关键是如果我们隐藏GetBaseDefinition()
方法,MethodInfo
将返回相同的MethodInfo
而不是基础virtual
。
override
关键字是必须的,而new
仅用于取消警告消息。因此,我们可以通过override
和new
与IsAbstract
和IsVirtual
的结合来区分DeclaringType
和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;
}
我使用简单的继承测试它,它的工作原理。我不考虑通用方法..但是..
编辑:我只是更改上面的代码,因为我忘记了有关继承类型的想法可以包含新声明的方法,该方法不应该作为新方法。 IsHiding()
首先会确保它具有相同的DeclaringType
(看起来像是新的),但如果存在具有相同名称的方法,则需要查看DeclaringType.BaseType
的基本声明类型。
请注意,由于没有BindingFlags.DeclaredOnly
,GetMethod()
将搜索整个基类型,因此无需递归搜索每种基类型。 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()
。测试的重载与不同参数组合使用,与ref
,out
,params
和可选参数混合使用。根据参数计数,参数类型及其修饰符比较过载的签名:
ref
或out
,但两者不能相互重载。params
应忽略 ref
与ParameterType
本身进行比较(请参阅调试期间的“&amp;”结尾),而IsByRef
与out
进行比较时无需进行比较。 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
隐藏方法的类型。
在泛型的情况下,所有方法都由模板类定义。