2010-09-21 228 views
2

内获取的所有基本属性声明考虑这一组有趣的类型:类层次结构

class A  { public virtual  int MyProperty { get; set; } } 
class B : A { public override int MyProperty { get; set; } } 
class C : B { public new virtual int MyProperty { get; set; } } 
class D : C { public override int MyProperty { get; set; } } 
class E : D { public new   int MyProperty { get; set; } } 

我在这里看到三个不同的性质,有五个实现隐藏或覆盖对方。

我试图让一组属性声明E类型:

A.MyProperty 
C.MyProperty 
E.MyProperty 

但我下面的代码给我的一套物业实现

A.MyProperty 
B.MyProperty 
C.MyProperty 
D.MyProperty 
E.MyProperty 

什么我需要做什么来获得财产声明?

或者B.MyProperty对于E的任何实例都会返回除A.MyProperty以外的值吗?

如果我的方法朝着错误的方向前进:如何获取某个类型的所有属性成员,包括隐藏的属性,但不包括那些永远不会具有不同值的属性?


void GetProperties(Type type) 
{ 
    if (type.BaseType != null) 
    { 
     GetProperties(type.BaseType); 
    } 

    foreach (var item in type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public)) 
    { 
     Console.WriteLine("{0}.{1}", type.Name, item.Name); 
    } 
} 

期望的产出:

 
typeof(A)  typeof(B)  typeof(C)  typeof(D)  typeof(E) 
------------ ------------ ------------ ------------ ------------ 
A.MyProperty A.MyProperty A.MyProperty A.MyProperty A.MyProperty 
           C.MyProperty C.MyProperty C.MyProperty 
                   E.MyProperty 
+0

我相信这是我第一次见到'新的虚拟。'花了我一秒来了解它的意图。 – Ani 2010-09-21 16:54:40

+1

我花了一段时间在反射物体上摸索如何做到这一点。我认为,一旦你找出如何用这些反射对象来表达它,这个问题会变得更加容易。找出它之后,我将这个问题重新解释为“列出指定类的所有基本属性声明”。 – 2010-09-21 17:45:34

回答

2

这可能让你开始下跌,你想要的路径:

static void GetProperties(Type type) 
    { 
     if (type.BaseType != null) 
     { 
      GetProperties(type.BaseType); 
     } 

     foreach (var item in type.GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public)) 
     { 
      MethodInfo method = item.GetGetMethod(); 
      MethodInfo baseMethod = method.GetBaseDefinition(); 

      System.Diagnostics.Debug.WriteLine(string.Format("{0} {1}.{2} {3}.{4}", type.Name, method.DeclaringType.Name, method.Name, baseMethod.DeclaringType, baseMethod.Name)); 

      if (baseMethod.DeclaringType == type) 
      { 
       Console.WriteLine("{0} {1}", type.Name, item.Name); 
      } 
     } 
    } 

该代码输出如下:

一个myProperty的

ÇmyProperty的

ËmyProperty的

请注意,此代码依赖于使用与该属性关联的get方法的MethodInfo。如果你碰巧拥有set-only属性,那么你需要做一些额外的检查来处理这种情况。

+0

'GetBaseDefinition'是我正在寻找的关键。谢谢! – dtb 2010-09-21 19:10:26

1

但不包括那些将永远不会有不同的价值观?

看来你期待Reflection系统为这个非常特殊的情况包含规则。如果确实如此,其他人会抱怨BD属性丢失。

但我想答案是:D.MyProperty是从递归调用中列出的。你知道你已经列出了E.MyProperty,所以它可能看起来没有必要,但如果你打电话GetProperties(D)?你希望它被省略吗?

+0

是的,当我调用'GetProperties(typeof(D))'时,我想省略'D.MyProperty'和'E.MyProperty'。 'D.MyProperty'因为它只是覆盖'C.MyProperty'和'E.MyProperty',因为'D'对'E'没有任何了解。我已经为我的问题添加了所有类型的所需输出。 – dtb 2010-09-21 17:39:33

0

这些都是声明和实现(因为它们都不是抽象的,所以它们都定义方法体)。关键字覆盖和新建只是给运行时提供了关于给定实例的上下文选择哪个实现的提示。通过反射,您可以绕过正常的继承跟踪并调用特定的实现。

鉴于此,您仍然可以找出哪些是由层次结构中的各个点构成的“根”调用。回想一下,.NET中的属性对于特定的getter和setter方法结构和一个后台字段来说是相当多的语法糖,就像访问器是字段本身一样访问。因此,一个PropertyInfo公开GetGetMethod()GetSetMethod()这将返回MethodInfo对象。你应该只需要其中的一个,因为它们都具有赋予属性的继承限定符,但要确保你的属性在层次结构的所有级别都有一个get或set,否则这将会炸毁。

现在,MethodInfo公开了几个关于可访问性和继承性的属性。对你来说重要的是IsHideBySig属性。如果这返回true,那么在当前类型中声明的此方法使用new关键字在其父项上隐藏相同的签名。所以,在你的代码中,你想看看成员,并测试两件事情;该类型是否具有除Object(或您指定的抽象类型)之外的基本类型以及是否为getter或setter上的IsHideBySig为真。如果其中任何一个为真,则对于当前类型与具有类似“根”的下一个派生类型之间的任何类型,这是“根”实现。

所以,你foreach最终会看起来像这样:

foreach (var item in type.GetProperties(
    BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public) 
     .Where(pi=>pi.GetGetMethod().IsHideBySig || pi.ReflectedType.BaseType == typeof(Object)) 
{ 
     Console.WriteLine("{0} {1}", type.Name, item.Name); 
} 

现在还记得,这些“根”是不是会被调用,除非他们的孩子使用base标识显式调用他们的,无论当前属性是隐藏还是覆盖其父项,都可能发生这种情况。不同之处在于,当实例被转换为其祖先类型之一时,运行时将调用实现。在这种情况下,所选择的实现是类型转换类型和实际类型之间的继承链中最具派生类型的实现,从不隐藏父类型的转换类型开始。如果转换类型的最直接后代隐藏其父类型,则无论该实现对其父类执行什么操作,都会使用转换类型的实现。

在你的层次结构中,那些是B,D和E.如果你声明了一个新的E并且调用了MyProperty,你会得到E的实现。然后,如果您将它传递给采用任何A并访问MyProperty的方法,它将使用B的实现。如果你宣布一个E并把它当作一个C,它将使用D的实现。如果你创建了一个C并且像这样对待它,你会得到C的实现(因为C不是D),但是如果你把它当作一个A来实现,那么你会得到B的实现。

+0

这听起来很有趣,但代码不会以其当前形式产生期望的结果。 – dtb 2010-09-21 19:07:52

+0

顺便说一句,你确切地想要得到我想要的:获取“根”列表并调用最多派生的实现。 – dtb 2010-09-21 19:09:31