2008-10-16 138 views
9

在C#中,當泛型列表僅包含基類時,訪問派生類屬性的最佳方式是什麼?從C#中的基類訪問派生類的屬性#

public class ClassA : BaseClass 
{ 
    public object PropertyA { get; set; } 
} 

public class ClassB: BaseClass 
{ 
    public object PropertyB { get; set; } 
} 

public class BaseClass 
{ 
} 

public void Main 
{ 
    List<BaseClass> MyList = new List<BaseClass>(); 
    ClassA a = new ClassA(); 
    ClassB b = new ClassB(); 

    MyList.Add(a); 
    MyList.Add(b); 

    for(int i = 0; i < MyList.Count; i++) 
    { 
     //I would like to access PropertyA abd PropertyB from the derived classes   
    } 
} 

回答

19

當然,你可以垂頭喪氣,像這樣:

for (int i = 0; i < MyList.Count; i++) 
{ 
    if (MyList[i] is ClassA) 
    { 
     var a = ((ClassA)MyList[i]).PropertyA; 
     // do stuff with a 
    } 

    if (MyList[i] is ClassB) 
    { 
     var b = ((ClassB)MyList[i]).PropertyB; 
     // do stuff with b 
    } 
} 

...但是,你應該再看看你要完成的任務。如果你的公共代碼需要到達ClassA和ClassB的屬性,那麼你最好將對這些屬性的訪問封裝到祖先類中的共享虛擬屬性或方法中。

喜歡的東西:

public class BaseClass 
{ 
    public virtual void DoStuff() { } 
} 

public class ClassA : BaseClass 
{ 
    public object PropertyA { get; set; } 

    public override void DoStuff() 
    { 
     // do stuff with PropertyA 
    } 
} 

public class ClassB : BaseClass 
{ 
    public object PropertyB { get; set; } 

    public override void DoStuff() 
    { 
     // do stuff with PropertyB 
    } 
} 
+1

我使用第二個代碼示例訪問我的派生類中的屬性......感謝您的輸入。 – 2008-10-17 00:53:28

+1

這太棒了。我搜索了很高的和低的,並且遇到很多說這是不可能的線程,但是這個解決方案是絕對有效的。 – Caustix 2012-01-17 19:14:34

1

整體前提是沒有意義的 - 你會PropertyB是爲A實例?

如果您執行手動運行時類型檢查(inst爲Foo),然後將其轉換爲具有所需屬性的類型,則可以執行此操作。

1
BaseClass o = MyList[i]; 
    if (o is ClassB) 
    { 
     object k = ((ClassB)o).PropertyB; 
    } 
    if (o is ClassA)) 
    { 
     object j = ((ClassA)o).PropertyA; 
    } 
0

你可能有泛型和子類(在這種情況下,你應該回去System.Collections.ArrayList)一些問題,但你必須在BaseClass的強制轉換爲您希望使用的子類。如果你使用'as'目錄,那麼如果BaseClass可以被轉換成子類,它將會成功,否則如果它不能被轉換,它將是空的。它看起來像這樣:

for(int i = 0; i < MyList.Count; i++) 
{ 
    BaseClass bc = MyList[i]; 
    ClassA a = bc as ClassA; 
    ClassB b = bc as ClassB; 
    bc.BaseClassMethod(); 
    if (a != null) { 
     a.PropertyA; 
    } 
    if (b != null) { 
     b.PropertyB; 
    } 
} 

另外,我應該提到,這味道有點不好。這是代表結構不良的對象的代碼。一般來說,如果你不能說IS是一個BaseClass,你的設計可能是錯誤的。但是,希望有所幫助!

2

如果你這樣做了很多,另一種選擇是創建名單上的擴展方法來給你回的正確類型的枚舉。即

public static class MyBaseListExtensions 
    { 
    public static IEnumerable<ClassA> GetAllAs(this List<MyBaseClass> list) 
    { 
     foreach (var obj in list) 
     { 
     if (obj is ClassA) 
     { 
      yield return (ClassA)obj; 
     } 
     } 
    } 

    public static IEnumerable<ClassB> GetAllbs(this List<MyBaseClass> list) 
    { 
     foreach (var obj in list) 
     { 
     if (obj is ClassB) 
     { 
      yield return (ClassB)obj; 
     } 
     } 
    } 
    } 

然後,你可以用它喜歡....

private void button1_Click(object sender, EventArgs e) 
{ 
    ClassA a1 = new ClassA() { PropertyA = "Tim" }; 
    ClassA a2 = new ClassA() { PropertyA = "Pip" }; 
    ClassB b1 = new ClassB() { PropertyB = "Alex" }; 
    ClassB b2 = new ClassB() { PropertyB = "Rachel" }; 

    List<MyBaseClass> list = new List<MyBaseClass>(); 
    list.Add(a1); 
    list.Add(a2); 
    list.Add(b1); 
    list.Add(b2); 

    foreach (var a in list.GetAllAs()) 
    { 
    listBox1.Items.Add(a.PropertyA); 
    } 

    foreach (var b in list.GetAllbs()) 
    { 
    listBox2.Items.Add(b.PropertyB); 
    } 
} 
0

您需要有屬性被聲明爲虛基類,然後在派生類中重寫它們。

例:

public class ClassA : BaseClass 
{ 
    public override object PropertyA { get; set; } 
} 

public class ClassB: BaseClass 
{ 
    public override object PropertyB { get; set; } 
} 

public class BaseClass 
{ 
    public virtual object PropertyA { get; set; } 
    public virtual object PropertyB { get; set; } 
} 

public void Main 
{ 
    List<BaseClass> MyList = new List<BaseClass>(); 
    ClassA a = new ClassA(); 
    ClassB b = new ClassB(); 

    MyList.Add(a); 
    MyList.Add(b); 

    for(int i = 0; i < MyList.Count; i++) 
    { 
    // Do something here with the Property 
     MyList[i].PropertyA; 
     MyList[i].PropertyB;  
    } 
} 

你要麼需要實現在基類的屬性返回默認值(例如null)或使其抽象,並迫使所有派生類來實現這兩個屬性。

您還應該注意,您可以通過在派生類中重寫它並返回不同的值來返回PropertyA的不同內容。

5

繼TimJ的答案,你可以寫一個擴展方法,將所有類型的工作:

public static IEnumerable<T> OfType<T>(this IEnumerable list) 
{ 
    foreach (var obj in list) 
    { 
     if (obj is T) 
      yield return (T)obj; 
    } 
} 

或者,如果你有LINQ中,該功能是在命名空間System.Linq的。

相關問題