2010-09-21 226 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