我也试着找到这个东西。从问题中,你给出了使用override
关键字来使IsOverriding
起作用的想法。然而,对于隐藏,我试图创建new
关键字的IsHiding
。以下是基本的C# OOP:
override
仅在基方法包含abstract
或virtual
修饰符时使用。
new
用于隐藏具有相同名称但...
new
不能应用于abstract
基本方法,因为它会生成编译器错误。
- 然而,有趣的部分是,如果基方法包含
virtual
,则还可以将new
应用于方法。
有趣的部分是我们可以隐藏或覆盖virtual
方法。我们知道,如果我们重写virtual
方法,则GetBaseDefinition()
将返回基MethodInfo
。但是区分它的关键是,如果我们隐藏virtual
方法,则GetBaseDefinition()
将返回相同的MethodInfo
而不是它的基MethodInfo
。
override
关键字是必须的,而new
仅用于抑制警告消息。因此,我们可以通过IsAbstract
和IsVirtual
与DeclaringType
和BaseType
相结合来区分override
和new
。
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()
方法,以检查基本方法重载并使用GetMethods()
而不是GetMethod()
来防止AmbiguousMatchException
。测试过的重载与不同参数的组合一起工作,与ref
、out
、params
和可选参数混合使用。基于参数计数、参数类型及其修饰符比较重载的签名:
ref
或out
包含在签名中,但不能相互重载。
- 返回类型、可选(默认值)和右侧最后一个参数上的
params
应被忽略。
ref
通过ParameterType
本身进行比较(在调试期间查看结尾'&'),不需要通过IsByRef
进行比较,而out
则通过Attributes
标志进行比较。我使用简化的按位异或表达式,仅在其中一个属性具有Out
标志使签名不同的情况下跳过循环。不要与.NET 4中的HasFlag
混淆,它只想确保XOR结果中的Out
位为1。