2013-07-30 37 views
8

Bối cảnh: .NET 4.0, C#C# Sử dụng generics và thực hiện giao diện

Tôi đang tạo một tập hợp các giao diện và một tập hợp các phép thực hiện chúng để cung cấp một số dịch vụ. Các máy khách sử dụng các clases cụ thể nhưng các phương thức gọi được khai báo sử dụng các giao diện như các kiểu tham số.

Một ví dụ đơn giản là thế này một:

namespace TestGenerics 
{ 
    // Interface, of fields 
    interface IField 
    { 
    } 

    // Interface: Forms (contains fields) 
    interface IForm<T> where T : IField 
    { 

    } 

    // CONCRETE CLASES 
    class Field : IField 
    { 
    } 

    class Form <T> : IForm<T> where T : IField 
    { 
    } 

    // TEST PROGRAM 
    class Program 
    { 
     // THIS IS THE SIGNATURE OF THE METHOD I WANT TO CALL 
     // parameters are causing the error. 
     public static void TestMethod(IForm<IField> form) 
     { 
      int i = 1; 
      i = i * 5; 
     } 

     static void Main(string[] args) 
     { 
      Form<Field> b = new Form<Field>(); 
      Program.TestMethod(b); 
     } 
    } 
} 

Mã này có ý nghĩa với tôi, nhưng tôi nhận được lỗi biên dịch:

Argument 1: cannot convert from ' TestGenerics.Form<TestGenerics.Field> ' to ' TestGenerics.IForm<TestGenerics.IField> ' TestGenerics

Tôi không chắc chắn những gì tôi đang làm sai , Tôi đã đọc rất nhiều trang trên internet nhưng không ai giải quyết được vấn đề của tôi.

Có một giải pháp mà sẽ không thay đổi mà nhiều kiến ​​trúc của những gì tôi đang cố gắng xây dựng:

Edit: Tôi thiết kế các giao diện theo cách như vậy mà họ cần phải độc lập với clases bê tông mà thực hiện chúng . Các clases cụ thể có thể được nạp từ một dll, nhưng hầu hết các ứng dụng Làm việc với các giao diện. Trong một số trường hợp, tôi cần phải sử dụng các xung đột cụ thể, đặc biệt khi sử dụng các clases cần phải được tuần tự hóa.

Xin cảm ơn trước.

Alejandro

+5

này sẽ thuộc lĩnh vực của hiệp phương sai. Cụ thể, nếu bạn thêm ['out' generic modifier] (http://msdn.microsoft.com/en-us/library/dd469487.aspx) vào chữ ký của bạn' interface IForm trong đó T: IField' thì nó sẽ hoạt động .Nhưng điều này cho biết thêm những hạn chế/cân nhắc khác vì vậy tôi không thể bình luận nếu nó có thể áp dụng cho thiết kế/sử dụng hiện tại của bạn. –

+2

Tôi tò mò bạn đang cố gắng làm gì với thiết kế này. – sidesinger

+0

Cảm ơn rất nhiều vì cả hai đều là những người bảo vệ. Tôi đã thêm một chỉnh sửa giải thích lý do tại sao tôi desinged các giải pháp theo cách đó, nhưng cả hai anwers có thể sửa chữa vấn đề của tôi. Trân trọng. – Sugar

Trả lời

13

Vấn đề là Form<Field> thực hiện IForm<Field> nhưng không IForm<IField>. Bạn không thể sử dụng lớp thừa kế (hoặc giao diện) làm tham số chung trừ khi nó được đánh dấu là biến thể với mã định danh out. Tuy nhiên, việc đánh dấu giao diện của bạn là biến thể sẽ hạn chế việc sử dụng một cách đáng kể (về cơ bản là tạo ra một giao diện "chỉ xuất" như IEnumerable) để nó có thể không hoạt động cho bạn.

Một cách để làm cho nó hoạt là làm cho TestMethod chung cũng như:

public static void TestMethod<T>(IForm<T> form) where T:IField 
{ 
    int i = 1; 
    i = i * 5; 
} 
10

Bạn có thể sử dụng Hiệp phương sai, như vậy:

interface IForm<out T> where T : IField 
{ 

} 

Thông tin thêm về Hiệp phương sai và Contravariance here.

+1

Hiệp phương sai khi bạn cho phép một lớp dẫn xuất được sử dụng như một tham số kiểu chung bằng cách sử dụng từ khóa "out". Trong liên kết tôi đã đăng, bạn có thể thấy câu này: "vì tham số kiểu của giao diện của IEnumerable là biến thể, bạn có thể gán một thể hiện của IEnumerable (IEnumerable (Of Derived) trong Visual Basic) thành một biến loại IEnumerable " –

7

Những người khác đã chỉ ra lý do đằng sau thông báo lỗi, nhưng hãy kiểm tra thiết kế mã mẫu của bạn trong giây lát. Có lẽ bạn đang sử dụng một chung chung, nơi không ai là cần thiết.

Bạn đã nói bạn đang sử dụng các phương thức được khai báo trong giao diện IField, vì vậy có thể không cần phải làm cho lớp IForm chung chung - chỉ cần lưu trữ tham chiếu đến IField, thay vì đối số chung 'T' (mà đã được đảm bảo là một IField anyway).

Ví dụ, sử dụng:

public interface IForm 
{ 
    IEnumerable<IField> Fields { get; set; } 
} 

thay vì

public interface IForm<T> where T : IField 
{ 
    IEnumerable<T> Fields { get; set; } 
} 
+0

Đồng ý. Một dấu hiệu khác là mã người tiêu dùng đã khởi tạo điều này dưới dạng IForm và Biểu mẫu , cho thấy IField là đủ. Các thử nghiệm thực sự là thời tiết hoặc không phải là loại bê tông T cần phải là một phần của API đối mặt bên ngoài. – Tormod

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