2008-10-16 13 views
9

In C#, was ist der beste Weg auf eine Eigenschaft der abgeleiteten Klasse zuzugreifen, wenn die generische Liste nur die Basisklasse enthält.Zugreifen auf eine Eigenschaft der abgeleiteten Klasse aus der Basisklasse in 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   
    } 
} 

Antwort

19

Natürlich können Sie niedergeschlagenen, etwa so:

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 
    } 
} 

... Aber Sie noch einen Blick sollte auf das, was Sie erreichen wollen. Wenn Sie über gemeinsamen Code verfügen, der Eigenschaften von ClassA und ClassB ermitteln muss, können Sie den Zugriff auf diese Eigenschaften besser in eine gemeinsame virtuelle Eigenschaft oder Methode in der Vorgängerklasse integrieren.

Etwas wie:

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

Ich benutzte das zweite Codebeispiel, um auf meine Eigenschaften in meinen abgeleiteten Klassen zuzugreifen ...... Danke für Ihre Eingabe. –

+1

Das ist brilliant. Ich suchte hoch und tief und stieß auf so viele Fäden, die sagten, das sei unmöglich, aber diese Lösung ist ein absoluter Leckerbissen. – Caustix

1

Die gesamte Prämisse macht keinen Sinn - was wäre PropertyB für die Instanz?

Sie können dies tun, wenn Sie die manuelle Überprüfung des Laufzeittyps (inst ist Foo) durchführen und dann in den Typ mit der gewünschten Eigenschaft umwandeln.

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

Sie könnten einige Probleme mit Generics und Unterklassen haben (in diesem Fall sollten Sie zu System.Collections.ArrayList zurück), aber Sie müssen die Baseclass in die Unterklasse Sie verwenden möchten, werfen. Wenn Sie das Verzeichnis 'as' verwenden, wird es erfolgreich ausgeführt, wenn die BaseClass in die Unterklasse umgewandelt werden kann, oder es wird null sein, wenn es nicht umgewandelt werden kann. Es würde ungefähr so ​​aussehen:

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; 
    } 
} 

Auch sollte ich erwähnen, dass dies ein wenig schlecht riecht. Dies ist die Art von Code, der auf eine schlecht strukturierte Objekthierarchie hinweist. Im Allgemeinen, wenn Sie eine IS A BaseClass nicht sagen können, ist Ihr Entwurf wahrscheinlich falsch. Aber, hoffe das hilft!

2

Wenn Sie diese viel tun, wäre eine weitere Option, eine Erweiterungsmethode auf der Liste erstellen Sie zurück, um die korrekte Schreibweise Aufzählung zu geben. das heißt

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; 
     } 
     } 
    } 
    } 

Dann könnte es Ihnen gefällt verwenden ....

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

Sie benötigen würden die Eigenschaften als virtuelle auf der Basisklasse deklariert werden zu lassen und sie dann in der abgeleiteten Klasse überschreiben.

Ex:

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;  
    } 
} 

würden Sie müssen entweder die Eigenschaft in der Basisklasse implementieren einen Standardwert (zB null) zurückzukehren, oder es abstrakt zu machen und alle abgeleiteten Klassen zwingen, beide Eigenschaften zu implementieren .

Sie sollten auch beachten, dass Sie verschiedene Dinge für say PropertyA zurückgeben können, indem Sie es in beiden abgeleiteten Klassen außer Kraft setzen und unterschiedliche Werte zurückgeben.

5

Zusätzlich zu TimJ Antwort, können Sie eine Erweiterungsmethode schreiben, die für alle Arten arbeiten:

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

Oder wenn Sie Linq haben, diese Funktion ist im Namensraum System.Linq.

+0

Ich mag diese Lösung auch .... Danke für die Information –

Verwandte Themen