2009-04-02 29 views
7

tôi đã loại sau đây:C# - đúc lớp tổng quát để cơ sở không chung lớp của nó

public abstract class CustomerBase 
{ 
    public long CustomerNumber { get; set; } 
    public string Name { get; set; } 
} 

public abstract class CustomerWithChildern<T> : CustomerBase 
    where T: CustomerBase 
{ 
    public IList<T> Childern { get; private set; } 

    public CustomerWithChildern() 
    { 
     Childern = new List<T>(); 
    } 
} 

public class SalesOffice : CustomerWithChildern<NationalNegotiation> 
{ 
} 

Các SalesOffice chỉ là một trong số ít các lớp đại diện cho mức độ khác nhau của hệ thống phân cấp của khách hàng. Bây giờ tôi cần phải đi qua hệ thống phân cấp này từ một số điểm (CustomerBase). Tôi không thể tìm ra cách thực hiện mà không sử dụng sự phản chiếu. Tôi muốn triển khai một cái gì đó như:

public void WalkHierarchy(CustomerBase start) 
    { 
     Print(start.CustomerNumber); 
     if (start is CustomerWithChildern<>) 
     { 
      foreach(ch in start.Childern) 
      { 
       WalkHierarchy(ch); 
      } 
     } 
    } 

Có cơ hội nào tôi có thể làm việc như thế này không?


Các giải pháp dựa trên gợi ý có-childern giao diện tôi thực hiện:

public interface ICustomerWithChildern 
{ 
    IEnumerable ChildernEnum { get; } 
} 

public abstract class CustomerWithChildern<T> : CustomerBase, ICustomerWithChildern 
    where T: CustomerBase 
{ 
    public IEnumerable ChildernEnum { get { return Childern; } } 

    public IList<T> Childern { get; private set; } 

    public CustomerWithChildern() 
    { 
     Childern = new List<T>(); 
    } 
} 

    public void WalkHierarchy(CustomerBase start) 
    { 
     var x = start.CustomerNumber; 
     var c = start as ICustomerWithChildern; 
     if (c != null) 
     { 
      foreach(var ch in c.ChildernEnum) 
      { 
       WalkHierarchy((CustomerBase)ch); 
      } 
     } 
    } 

Trả lời

2

Tôi tin rằng bạn muốn thực hiện tìm kiếm để xác định việc thực hiện giao diện đi bộ. Vì vậy, có thể thêm một giao diện "IWalkable" để lộ thông tin cần thiết để thực hiện bước đi, sau đó bạn có thể tạo phương thức kiểm tra để xem đối tượng được truyền có thực hiện giao diện hay không.

2

"Is" và "As" chỉ làm việc trên các loại generic đầy đủ.

Xem this MSDN discussion để biết chi tiết bao gồm cách giải quyết.

Cách giải quyết phổ biến nhất mà tôi thấy là thêm giao diện vào danh sách kết hợp mà CustomerWithChildren của bạn có thể triển khai và kiểm tra giao diện đó.

7

Bạn có thể di chuyển phương thức WalkHierarchy đến lớp cơ sở và biến nó thành ảo. Việc triển khai lớp cơ sở sẽ chỉ xử lý nút hiện tại. Đối với lớp CustomerWithChildern<T>, ghi đè sẽ thực hiện bước đi thực tế.

+0

Đây là giải pháp tốt nhất vì nó đóng gói thực hiện đi bộ và chỉ làm những điều đúng đắn mà không buộc người gọi phải nhận thức được các chi tiết thực hiện. – recursive

+0

Lời khen ngợi cao từ một người có tên, "đệ quy". ;-) –

+0

Dự án .NET lớn cuối cùng của tôi có yêu cầu tương tự, và cách của John Saunders giống như tôi đã làm. Làm nhiều thứ dễ dàng hơn nhiều :) – OregonGhost

0

Rõ ràng với phương pháp đó, không. Tuy nhiên bạn có thể đạt được chức năng tương tự với một giao diện. Trong thực tế, bạn chỉ có thể có lớp chung của bạn thực hiện IEnumerable. Nó cũng đáng chú ý là lớp học của bạn cũng nên có "nơi T: CustomerBase" để đảm bảo an toàn loại.

1

Tôi nghĩ mọi người sẽ truy cập "vấn đề" này khi lần đầu tiên làm việc với các lớp học chung.

Vấn đề đầu tiên của bạn được gợi ý trong câu hỏi của bạn: một loại generic mở không phải là lớp cơ sở cho lớp đóng. Không có mối quan hệ OO nào cả. Lớp cơ sở thực là CustomerBase. Một kiểu generic "mở" giống như một lớp đã hoàn thành một nửa; xác định các đối số kiểu "đóng" nó, làm cho nó hoàn thành.

Trong khi bạn có thể làm:

Type t = typeof(CustomerWithChildern<>) 

điều kiện

typeof(CustomerWithChildern<>).IsAssignableFrom(CustomerWithChildern<Foo>) 

sẽ luôn là False.

-Oisin

3

Hãy thử điều này:

if(start.GetType().GetGenericTypeDefinition() == typeof(CustomerWithChildern<>)) 
Các vấn đề liên quan