2012-06-10 28 views
6

Tôi là một người mới bắt đầu với C# và không thể tìm thấy bất kỳ câu trả lời cho điều này:Cách ủy quyền chính xác Hành động <Interface>?

Im cố gắng để ủy Hoạt động với một số thông số giao diện, nhưng đẩy thông qua chức năng với các đối tượng mà mở rộng giao diện này (hoặc lớp)

// some class extending interface 
public class IntEvent : IFace{} 
public class MoveEvent : IFace{} 

// function i like to use to verify Action 
static void setAction(Action<IFace> evt) { 
    // evt ... 
} 
// function to delegate as Action 
static void evtCheck(IntEvent evt) { 
    // some func 
} 
static void evtMove(MoveEvent evt) { 
    // some func 
} 
// class { 
// call method inside class and delegate this function : 
setAction(evtCheck); 
setAction(evtMove); 

Tôi nhận được lỗi "evtCheck(IntEvent) không thể chuyển đổi thành Action<IFace>", ngay cả khi IntEvent mở rộng giao diện IFace.

Tôi nên giải quyết vấn đề này bằng cách nào? Có lẽ tôi phải sử dụng Func hoặc Delegate?

Trả lời

7

Bạn không thể làm những gì bạn đang cố gắng làm - bạn mong đợi hiệp phương sai, nhưng Action<T>contravariant trên tham số loại duy nhất của nó.

Bạn không thể làm một chuyển đổi phương pháp nhóm evtCheck-Action<IFace>evtCheck cần một loại cụ thể hơn (IntEvent) như là đối số của nó so với tổng quát hơn IFace kiểu đó một thể hiện Action<IFace> hy vọng. Nếu một chuyển đổi như vậy được cho phép, bạn sẽ mong đợi điều gì sẽ xảy ra nếu đại biểu được thực hiện với một đối số thực hiện IFace nhưng không phải là một IntEvent? Tôi nghĩ bạn nên có một cái nhìn khác về thiết kế của bạn bởi vì có vẻ như có một lỗ hổng ở đó, nhưng nếu bạn muốn, bạn có thể tạo một lambda để ép một đối số cho kiểu mong muốn và chấp nhận khả năng của một InvalidCastException:

setAction(iFace => evtCheck((IntEvent)iface)); 

nhiều khả năng, bạn có thể muốn làm evtCheck chấp nhận một loại tổng quát hơn hoặc setAction để chấp nhận một đại biểu cụ thể hơn.

4

Action<T> là contravariant trong T, vì vậy phương pháp dùng một Action<T> cũng sẽ chấp nhận Action<U> nơi T có nguồn gốc từ U.

lớp IntEvent của bạn, tuy nhiên, thực hiện các giao diện IFace, có nghĩa là nếu trình biên dịch được chấp nhận setAction() của bạn cuộc gọi, bạn có thể gọi số evtCheck() với một đối số khác là IFace -chỉ dẫn và không IntEvent, lỗi thời gian chạy và vi phạm rõ ràng về an toàn loại.

buộc Eric Lippert tham khảo: Covariance and contravariance

EDIT: Từ mô tả của bạn có vẻ như với tôi rằng những gì bạn thực sự muốn là sự khác biệt dựa trên loại tham số phương pháp, vì vậy ví dụ bạn muốn có một hành động riêng biệt cho IntEvent, một hành động khác cho (giả thuyết) DoubleEvent v.v. Nếu đây là trường hợp, bạn thực sự là sau khi công văn ảo kép, không được hỗ trợ trực tiếp trong C#, nhưng bạn có thể mô phỏng nó bằng cách sử dụng mẫu thiết kế Visitor .

+0

Vâng, đây là những gì tôi đang cố gắng làm. Các hàm hành động luôn mong đợi đối tượng mở rộng cùng một giao diện hoặc đối tượng. Ok, tôi sẽ xem xét mẫu thiết kế của khách truy cập. – turbosqel

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