2009-07-21 30 views
36

Để cắt một câu chuyện dài, tôi có một hàm C# thực hiện một nhiệm vụ trên một Kiểu đã cho được truyền vào như một cá thể đối tượng. Tất cả đều hoạt động tốt khi một cá thể lớp được truyền vào. Tuy nhiên, khi đối tượng được khai báo là một giao diện, tôi thực sự muốn tìm lớp bê tông và thực hiện hành động theo kiểu lớp đó.Tìm Loại Bê tông phía sau một thể hiện Giao diện

Dưới đây là ví dụ phổ biến xấu (rực rỡ với tài sản không đúng vỏ vv):

public interface IA 
{ 
    int a { get; set; } 
} 
public class B : IA 
{ 
    public int a { get; set; } 
    public int b { get; set; } 
} 
public class C : IA 
{ 
    public int a { get; set; } 
    public int c { get; set; } 
} 

// snip 

IA myBObject = new B(); 
PerformAction(myBObject); 

IA myCObject = new C(); 
PerformAction(myCObject); 

// snip 

void PerformAction(object myObject) 
{ 
    Type objectType = myObject.GetType(); // Here is where I get typeof(IA) 
    if (objectType.IsInterface) 
    { 
     // I want to determine the actual Concrete Type, i.e. either B or C 
     // objectType = DetermineConcreteType(objectType); 
    } 
    // snip - other actions on objectType 
} 

Tôi muốn mã trong PerformAction sử dụng Reflection chống lại nó là tham số và thấy rằng nó không chỉ là một thể hiện của IA nhưng đó là một thể hiện của B và để xem thuộc tính "b" qua GetProperties(). Nếu tôi sử dụng .GetType() Tôi lấy kiểu IA - không phải cái tôi muốn.

Làm cách nào để PerformAction có thể xác định Loại bê tông cơ bản của cá thể IA?

Một số có thể bị cám dỗ đề xuất sử dụng lớp Tóm tắt nhưng đó chỉ là giới hạn của ví dụ xấu của tôi. Biến này ban đầu sẽ được khai báo là một thể hiện giao diện.

+7

Điều này nghe có vẻ tồi tệ. Bạn nên sử dụng đa hình thay vì có phương pháp của bạn biết về các loại cụ thể cụ thể. Điều gì sẽ xảy ra nếu bạn thêm sau? –

+4

Điều đó không đánh bại mục đích của một giao diện? Bạn không nên quan tâm loại bê tông là gì miễn là nó thực hiện giao diện. –

+2

+1 với John và Chris, không chỉ là thiết kế tồi, nhưng câu hỏi không có ý nghĩa gì cả. –

Trả lời

56
Type objectType = myObject.GetType(); 

vẫn nên cung cấp cho bạn các loại bê tông, theo ví dụ của bạn.

+2

Có, gọi "myObject.GetType()" wil KHÔNG BAO GIỜ trả về loại giao diện. – TcKs

+0

Tham số của 'PerfomAction' là' đối tượng', nhưng anh ta không thể làm: 'IA.getType()' cho ví dụ. –

2

Bạn không bao giờ có thể có phiên bản Giao diện. Vì vậy, xác định xem bạn đang giao dịch với một giao diện hoặc một loại cụ thể là không thể vì bạn sẽ luôn luôn được đối phó với một loại cụ thể. Vì vậy, tôi không chắc chắn bạn câu hỏi làm cho bất kỳ ý nghĩa. Chính xác thì bạn đang cố gắng làm gì và tại sao?

+2

+1 chính xác, trên thực tế ví dụ của anh ta hoạt động tốt. –

5

Bạn đang làm gì thực sự được thiết kế giường nhưng bạn không cần phải sử dụng phản ánh bạn có thể kiểm tra xem nó như thế này

void PerformAction(object myObject) 
{ 
    B objectType = myObject as B; // Here is where I get typeof(IA) 
    if (objectType != null) 
    { 
     //use objectType.b 
    } 
    else 
    { 
     //Same with A 
    } 
    // snip - other actions on objectType 
} 
+2

Đây vẫn là thiết kế khá xấu, vì bạn vẫn phụ thuộc vào loại bê tông. Điều này phần lớn đánh bại mục đích của việc có một giao diện ở nơi đầu tiên ... – jrista

+0

Tôi la hét trong đầu của tôi: "LSP, ISP, DIP !!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!! " – Sebastien

0

Có lẽ bạn đang tìm kiếm is operator

void PerformAction(object myObject) 
{ 
    if (myObject is B) 
    { 
     B myBObject = myObject as B; 
     myBObject.b = 1; 
    } 

    if (myObject is C) 
    { 
     C myCObject = myObject as C; 
     myCObject.c = 1; 
    } 

    // snip - other actions on objectType 
} 
+0

bạn đang truyền hai lần. Sử dụng toán tử 'as' ngay lập tức và kiểm tra null sau – nawfal

4

tôi phải đồng ý về thiết kế xấu. Nếu bạn có một giao diện, nó phải là do bạn cần sử dụng một số chức năng phổ biến mà không cần quan tâm đến việc thực hiện cụ thể là gì. Giả sử bạn là ví dụ, có vẻ như phương thức PerformAction thực sự là một phần của giao diện:

public interface IA 
{ 
    int a { get; set; } 
    void PerformAction(); 
} 

public class B: IA 
{ 
    public int a { get; set; } 
    public int b { get; set; } 

    public void PerformAction() 
    { 
     // perform action specific to B 
    } 
} 

public class C : IA 
{ 
    public int a { get; set; } 
    public int c { get; set; } 

    public void PerformAction() 
    { 
     // perform action specific to C 
    } 
} 

void PerformActionOn(IA instance) 
{ 
    if (instance == null) throw new ArgumentNullException("instance"); 

    instance.PerformAction(); 

    // Do some other common work... 
} 


B b = new B(); 
C c = new C(); 

PerformActionOn(b); 
PerformActionOn(c); 
Các vấn đề liên quan