考虑以下变体:
class A
{
public virtual void Doit()
{
}
}
class B : A
{
public new virtual void Doit()
{
}
}
或
class B : A
{
public override virtual void Doit()
{
}
}
我找不到调用typeof(B).GetMethod("Doit");
在这两种情况下,MethodInfo.DecalringType
都是B类,其他属性看起来是一样的。
我错过了什么或者没有办法区分它们吗?
的更新
当我在LINQPAd中运行示例时,我注意到Attributes
属性中的细微差别:
for new virtual
值为 - PrivateScope,Public,Virtual,HideBySig, VtableLayoutMask
for override
- PrivateScope,Public,Virtual,HideBySig
更新2:
我用Google搜索VtableLayoutMask
并回到StackOverflow
Udate 3:
结果代码:
public static class MethodInfoExtensions
{
public static bool IsOverriden(this MethodInfo method)
{
Contract.Requires<ArgumentNullException>(method != null, "method");
return method.IsVirtual
&& !method.IsStatic
// overriden exactly in this class
&& method.ReflectedType == method.DeclaringType
// not new and not declared for the first time in the class
&& method.GetBaseDefinition() != method;
}
}
答案 0 :(得分:4)
更新:文档似乎暗示IsHideBySig
就是答案,但在实践中似乎并非如此。
另一种策略是依赖于NewSlot属性的存在:
public static bool HasNewModifier(this MethodInfo method)
{
return (method.Attributes & MethodAttributes.VtableLayoutMask)
== MethodAttributes.NewSlot;
}
原始的,错误的答案如下。
您可以依赖IsHideBySig属性。如果方法具有true
修饰符,则为new
。
请注意,上述内容仅适用于 C#方法。文档详细说明:
使用C#
new
修饰符声明派生类中的成员时 或Visual BasicShadows
修饰符,它可以隐藏相同的成员 基类中的名称。 C#通过签名隐藏基类成员。那 是,如果基类成员有多个重载,那么唯一的一个 隐藏的是具有相同签名的那个。相比之下, Visual Basic隐藏所有基类重载。因此,IsHideBySig
对使用Visual Basicfalse
声明的成员返回Shadows
修饰符,以及使用C#true
修饰符声明的成员上的new
。
答案 1 :(得分:3)
DeclaringType
如果隐藏new
,则会有所不同。例如,运行:
public class A
{
public virtual void WillBeInheritted()
{
}
public virtual void WillBeOverridden()
{
}
public virtual void WillBeHidden()
{
}
}
public class B : A
{
public override void WillBeOverridden()
{
}
public virtual new void WillBeHidden()
{
}
}
class Program
{
public static void Main(string[] args)
{
foreach(var meth in typeof(B).GetMethods())
{
Console.Write(meth.Name);
Console.Write(": ");
Console.Write(meth.GetBaseDefinition().DeclaringType.Name);
Console.Write(" ");
Console.WriteLine(meth.DeclaringType.Name);
}
Console.Read();
}
}
输出将是:
WillBeOverridden: A B
WillBeHidden: B B
WillBeInheritted: A A
WillBeHidden: A A
ToString: Object Object
Equals: Object Object
GetHashCode: Object Object
GetType: Object Object
WillBeInheritted
有A
作为方法和基本定义的声明类型的声明类型。
WillBeOverridden
对于基本定义的声明类型有A
,声明类型为B
。
WillBeHidden
有两个版本,A
中隐藏的版本和B
中的隐藏版本。当我们考虑时,这是有道理的:
B b = new B();
A a = b;
b.WillBeHidden(); // calls hiding method.
a.WillBeHidden(); // calls hidden method on same object.
答案 2 :(得分:2)
您可以使用 GetBaseDefinition
查找首次声明此方法的位置。
例如,如果您允许var mi = typeof(B).GetMethod("Doit");
,则可以检查mi.GetBaseDefinition() == mi
或mi.GetBaseDefinition().DeclaringType == typeof(B)
等。
以下是一个例子:
class Animal : object
{
public virtual void M()
{
}
}
class Mammal : Animal
{
public override void M()
{
}
}
class Giraffe : Mammal
{
}
static class Test
{
internal static void Run()
{
var mi = typeof(Giraffe).GetMethod("M");
Console.WriteLine(mi.ReflectedType); // Giraffe
Console.WriteLine(mi.DeclaringType); // Mammal
Console.WriteLine(mi.GetBaseDefinition().DeclaringType); // Animal
}
}
MethodInfo
实例mi
表示override
继承(未更改)为Giraffe
。而mi.GetBaseDefinition()
会抓取另一个MethodInfo
代替方法Animal.M
,该方法不会在C#源中带有override
关键字。