2008-10-16 22 views
9

En C#, ¿cuál es la mejor forma de acceder a una propiedad de la clase derivada cuando la lista genérica contiene solo la clase base?Acceso a una propiedad de clase derivada de la clase base en 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   
    } 
} 

Respuesta

19

Ciertamente, usted puede abatido, así:

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

... Sin embargo, debe tomar otro vistazo a lo que estamos tratando de lograr. Si tiene un código común que necesita llegar a las propiedades de ClassA y ClassB, entonces será mejor que ajuste el acceso a esas propiedades en una propiedad o método virtual compartido en la clase ancestra.

Algo así como:

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

Utilicé la segunda muestra de código para acceder a mis propiedades en mis clases derivadas ...... Gracias por su contribución. –

+1

Esto es brillante. Busqué alto y bajo y encontré muchos hilos que decían que esto era imposible, pero esta solución funciona de manera absoluta. – Caustix

1

La premisa completa no tiene sentido, ¿qué sería PropertyB para una instancia?

Puede hacerlo si hace una comprobación manual del tipo de tiempo de ejecución (inst es Foo), y luego lo convierte al tipo con la propiedad que desea.

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

Es posible que tenga algunos problemas con los genéricos y subclases (en cuyo caso se debe volver a System.Collections.ArrayList), pero hay que emitir los BaseClass a la subclase que desea utilizar. Si utiliza el directorio 'como', tendrá éxito si BaseClass se puede convertir a la subclase, o será nulo si no se puede convertir. Se vería algo así como:

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

Además, debo mencionar que esto huele un poco mal. Este es el tipo de código que indica una jerarquía de objetos mal estructurados. En general, si no puede decir IS IS BaseClass, su diseño probablemente sea incorrecto. Pero, ¡espero que eso ayude!

2

Si usted está haciendo esto mucho, otra opción sería la creación de un método de extensión en la lista para darle vuelta la enumeración correctamente escrito. es decir,

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

entonces usted podría utilizarlo como ....

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

que tendría que tener las propiedades serán declarados como virtual en la clase base y luego anularlos en la clase derivada.

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

Usted sea necesario para implementar la propiedad en la clase base para devolver un valor por defecto (como nulo) o para que sea abstracto y obligar a todas las clases derivadas para implementar ambas propiedades .

También debe tener en cuenta que podría devolver cosas diferentes para decir PropertyA anulándolo en ambas clases derivadas y devolviendo valores diferentes.

5

con la respuesta de TimJ, puede escribir un método de extensión que funcione para todos los tipos:

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

O si tiene LINQ, esa función es en el espacio de nombres System.Linq.

+0

Me gusta esta solución también .... Gracias por la información –

Cuestiones relacionadas