2008-10-16 68 views
9

Trong C#, cách tốt nhất để truy cập thuộc tính của lớp dẫn xuất là gì khi danh sách chung chứa chỉ lớp cơ sở.Truy cập thuộc tính của lớp dẫn xuất từ ​​lớp cơ sở trong 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   
    } 
} 

Trả lời

19

Chắc chắn bạn có thể nhìn xuống, như vậy:

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

... Tuy nhiên, bạn nên xem xét thêm về những gì bạn đang cố gắng để đạt được. Nếu bạn có mã phổ biến cần đến các thuộc tính của ClassA và ClassB, thì bạn có thể tốt hơn việc ngắt quyền truy cập vào các thuộc tính đó thành một thuộc tính hoặc phương thức ảo được chia sẻ trong lớp tổ tiên.

Cái gì như:

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

Tôi đã sử dụng mẫu mã thứ hai để truy cập các thuộc tính của tôi trong các lớp dẫn xuất của tôi ...... Cảm ơn bạn đã nhập. –

+1

Điều này thật tuyệt vời. Tôi tìm kiếm cao và thấp và đi qua rất nhiều chủ đề cho biết điều này là không thể nhưng giải pháp này hoạt động một điều trị tuyệt đối. – Caustix

1

Toàn bộ tiền đề không có ý nghĩa - PropertyB sẽ là gì?

Bạn có thể thực hiện việc này nếu bạn thực hiện kiểm tra loại thời gian chạy thủ công (inst là Foo) và sau đó truyền đến loại có thuộc tính bạn muốn.

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

Bạn có thể có một số vấn đề với Generics và các lớp con (trong trường hợp này bạn nên trở về System.Collections.ArrayList), nhưng bạn phải cast BaseClass đến lớp con bạn muốn sử dụng. Nếu bạn sử dụng thư mục 'as', nó sẽ thành công nếu lớp BaseClass có thể được đúc thành lớp con, hoặc nó sẽ là null nếu nó không thể được đúc. Nó sẽ trông giống như:

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

Ngoài ra, tôi nên đề cập đến điều này có mùi hơi xấu. Đây là loại mã chỉ ra một cấu trúc thừa kế đối tượng có cấu trúc kém. Nói chung, nếu bạn không thể nói IS A BaseClass, thiết kế của bạn có lẽ là sai. Nhưng, hy vọng rằng sẽ giúp!

2

Nếu bạn đang làm điều này rất nhiều, tùy chọn khác sẽ được tạo ra một phương pháp khuyến nông trên danh sách để cung cấp cho bạn phía sau liệt kê gõ chính xác. ví dụ:

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

Sau đó, bạn có thể sử dụng nó như thế ....

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

Bạn sẽ cần phải có các thuộc tính được khai báo là ảo trên lớp cơ sở và sau đó ghi đè lên chúng trong lớp dẫn xuất.

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

Bạn có thể sẽ cần phải thực hiện các tài sản trong lớp cơ sở để trả về một giá trị mặc định (như null) hoặc để làm cho nó trừu tượng và buộc tất cả các lớp học có nguồn gốc thực hiện cả hai thuộc tính .

Bạn cũng nên lưu ý rằng bạn có thể trả về các thứ khác nhau để nói PropertyA bằng cách ghi đè nó trong cả hai lớp dẫn xuất và trả về các giá trị khác nhau.

5

Tiếp tục câu trả lời TimJ, bạn có thể viết một phương pháp mở rộng mà sẽ làm việc cho tất cả các loại:

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

Hoặc nếu bạn có LINQ, chức năng đó là trong System.Linq namespace.

+0

Tôi thích giải pháp này cũng .... Cảm ơn thông tin –

Các vấn đề liên quan