2009-07-28 15 views
5

Tôi có phương pháp chungTôi có thể hạn chế phương thức chung cho nhiều giao diện không?

public static void DoSomething<T>() 
{...} 

. Bây giờ tôi muốn hạn chế mà T.

public static void DoSomething<T>() where T: IInterface1 
{...} 

Nhưng những gì tôi thực sự muốn được cho phép nhiều giao diện, một cái gì đó giống như

public static void DoSomething<T>() where T: IInterface1, IInterface2 
{...} 

Nhưng điều đó không làm việc. Trình biên dịch nói điều gì đó giống như

There's no implicit conversion from IInterface1 to IInterface2

There's no implicit conversion from IInterface2 to IInterface1

Tôi nghĩ về việc cho phép các lớp thực hiện một giao diện chung mà tôi có thể tham khảo nhưng tôi không có quyền truy cập vào các lớp học.

Tôi có khả năng cho phép nhiều Giao diện?

Cảm ơn, Tobi

Edit: Đây là những gì tôi muốn làm. Tôi đang phát triển Outlook-Add-In. Tôi sử dụng đoạn mã dưới đây khá thường xuyên.

public static object GetItemMAPIProperty<T>(AddinExpress.MAPI.ADXMAPIStoreAccessor adxmapiStoreAccessor, object outlookItem, uint property) where T: Outlook.MailItem, Outlook.JournalItem 
    { 
     AddinExpress.MAPI.MapiItem mapiItem; 
     mapiItem = adxmapiStoreAccessor.GetMapiItem(((T)outlookItem)); 
     return mapiItem != null ? mapiItem.GetProperty(property) : null; 
    } 

Phương thức GetMapiItem có đối tượng miễn là một trong các mục của Outlook (Nhật ký, Thư, Liên hệ, ...). Đó là lý do tại sao tôi đã hạn chế T. Bởi vì nó không thể được, nói, Outlook.MAPIFolder.

Không, tôi đã thay đổi phương pháp để

public static object GetItemMAPIProperty<T>(AddinExpress.MAPI.ADXMAPIStoreAccessor adxmapiStoreAccessor, T outlookItem, uint property) 
    { 
     AddinExpress.MAPI.MapiItem mapiItem; 
     mapiItem = adxmapiStoreAccessor.GetMapiItem(((T)outlookItem)); 
     return mapiItem.GetProperty(property); 
    } 

nhưng nhà phát triển (Trong trường hợp này I) có thể cung cấp cho nó bất kỳ loại vì phương pháp GetMapiItem chấp nhận một đối tượng. Tôi hy vọng điều đó đúng. Tôi không chắc chắn nếu nó làm cho ví dụ đó nhưng tôi đoán hạn chế một phương pháp chung cho nhiều loại (với OR) có thể là một ý tưởng tốt.

+0

Bạn đang nhắm mục tiêu vào khung nào và bạn đang biên soạn với Visual Studio và phiên bản nào? Tôi có ở đây VS 2008 với NET 3.5 và các biên dịch trên chỉ tốt. Bạn có chắc chắn những gì bạn đang đưa cho chúng tôi như ví dụ là những gì bạn có. –

+1

bởi vì theo cách đó bạn nói trình biên dịch T nên là IInterface1 và IInterface2 không hoặc –

+0

mã mà anh ấy cung cấp, anh ấy chỉ cần nói phương thức lấy tham số kiểu IInterface1 OR IInterface2 –

Trả lời

1

một cách là để tạo ra một giao diện bổ sung mà kéo dài cả hai, Interface1 và 2. Sau đó bạn đặt giao diện này thay vì người kia 2.

đó là một cách để làm điều đó trong java; nếu tôi nhớ chính xác điều này cũng sẽ hoạt động tốt trong C#

hy vọng điều đó sẽ hữu ích.

liên quan, tobi: P

+0

Bạn đã quay lại. Điều này sẽ không hoạt động trong C#. –

+0

Bạn sẽ nhận được một lỗi thời gian biên dịch: Không có chuyển đổi tham chiếu ngầm từ (IInterface1 || IInterface2) đến (Tên Giao diện Mở rộng Cả hai). –

3

Có Interface1 và Interface2 đều xuất phát từ cùng một giao diện cơ sở. Ví dụ:

public static void DoSomething<T>() where T : ICommon 
    { 
     //... 
    } 

    public interface IInterface1 : ICommon 
    {} 

    public interface IInterface2 : ICommon 
    { } 

    public interface ICommon 
    { } 

Lợi ích của việc làm theo cách này là bạn không phải tiếp tục cập nhật định nghĩa DoSomething() mỗi khi bạn thêm giao diện mới kế thừa từ ICommon.

Chỉnh sửa: nếu bạn không có quyền kiểm soát giao diện, bạn có một vài tùy chọn. Đây là một điều mà bạn có thể làm ...

protected static class DoSomethingServer<T1> where T1 : class 
    { 

     //Define your allowed types here 
     private static List<Type> AllowedTypes = new List<Type> { 
      typeof(IInterface1), 
      typeof(IInterface2) 
     }; 

     public static MethodInvoker DoSomething() 
     { 
      //Perform type check 
      if (AllowedTypes.Contains(typeof(T1))) 
      { 
       return DoSomethingImplementation; 
      } 
      else 
      { 
       throw new ApplicationException("Wrong Type"); 
      } 
     } 

     private static void DoSomethingImplementation() 
     { 
      //Actual DoSomething work here 
      //This is guaranteed to only be called if <T> is in the allowed type list 
     } 
    } 

Sử dụng như vậy:

DoSomethingServer<IInterface1>.DoSomething(); 

Thật không may, điều này làm mất đi biên dịch an toàn kiểu thời gian và nó sẽ chỉ thổi lên trong thời gian chạy nếu bạn cố gắng ăn trong các loại sai. Rõ ràng đây là ít hơn lý tưởng.

+0

nó thậm chí có thể là một giao diện giữ chỗ trống, IStorable –

+1

Từ câu hỏi: "Tôi nghĩ về việc cho phép các lớp thực hiện một giao diện chung mà tôi có thể tham khảo nhưng tôi không có quyền truy cập vào các lớp." Dường như các giao diện có thể bị thay đổi sau đó. –

2

này biên dịch tốt cho tôi:

interface I1 { int NumberOne { get; set; } } 
interface I2 { int NumberTwo { get; set; } } 

static void DoSomething<T>(T item) where T:I1,I2 
{ 
    Console.WriteLine(item.NumberOne); 
    Console.WriteLine(item.NumberTwo); 
} 

Vì vậy, cú pháp có vẻ tốt đẹp ... có lẽ một cái gì đó nó khác đó là gây ra vấn đề.

+2

Bạn đã thử sử dụng phương pháp chưa? – James

+3

Tất nhiên điều này làm việc trong C#, nó chỉ làm những gì nó được cho là: nó định nghĩa một phương thức chỉ chấp nhận một 'mục' hỗ trợ giao diện BOTH. –

+0

Ah, nhận xét tôi trả lời đã biến mất. –

1
public interface IInterfaceBase 
    { 

    } 
    public interface IInterface1 : IInterfaceBase 
    { 
     ... 
    } 
    public interface IInterface2 : IInterfaceBase 
    { 
     ... 
    } 

    public static void DoSomething<T>() where T: IInterfaceBase 
    { 
    } 

Nếu bạn muốn T là IInterface1 hoặc IInterface2 sử dụng đoạn mã trên

+0

+1 điều này sẽ làm điều đó, nếu anh ta chỉ tìm kiếm cả hai loại để có một số mặt hàng chung. – Maslow

2

Nếu bạn có nghĩa là tham số có thể là một thực hiện I1 HOẶC một thực hiện I2, và họ là loại không liên quan, sau đó bạn không thể viết một nhóm phương thức (tức là quá tải với cùng tên phương thức) để xử lý cả hai loại.

Bạn thậm chí không thể nói (vay từ Nader!):

interface I1 { int NumberOne { get; set; } } 
    interface I2 { int NumberTwo { get; set; } } 

    static void DoSomething<T>(T item) where T : I1 
    { 
     Console.WriteLine(item.NumberOne); 
    } 

    static void DoSomething<T>(T item) where T : I2 
    { 
     Console.WriteLine(item.NumberTwo); 
    } 

    static void DoSomething<T>(T item) where T : I1, I2 
    { 
     Console.WriteLine(item.NumberOne); 
     Console.WriteLine(item.NumberTwo); 
    } 

Điều này sẽ cung cấp cho các trình biên dịch một cách để đối phó với mọi khả năng mà không mơ hồ. Nhưng để hỗ trợ việc tạo phiên bản, C# cố gắng tránh các tình huống khi thêm/xóa phương thức sẽ thay đổi khả năng áp dụng của phương thức khác.

Bạn cần phải viết hai phương thức với các tên khác nhau để xử lý hai giao diện.

+0

nếu DoSomething không nên tham số thì sao? –

+0

Không tạo sự khác biệt. Bạn cần viết một phương thức cho mỗi giao diện, và cung cấp cho các phương thức các tên khác nhau. –

+0

OR thừa kế có một công việc xung quanh với việc gõ vịt sắp tới và C# 4.0 – Maslow

0

Xây dựng những gì Earwicker đã nói ... tên không phải là cách duy nhất để đi. Bạn cũng có thể thay đổi chữ ký phương pháp ...

public interface I1 { int NumberOne { get; set; } } 
public interface I2 { int NumberTwo { get; set; } } 

public static class EitherInterface 
{ 
    public static void DoSomething<T>(I1 item) where T : I1 
    { 
     Console.WriteLine("I1 : {0}", item.NumberOne); 
    } 

    public static void DoSomething<T>(I2 item) where T : I2 
    { 
     Console.WriteLine("I2 : {0}", item.NumberTwo); 
    } 
} 

nào khi thử nghiệm như thế này:

public class Class12 : I1, I2 
{ 
    public int NumberOne { get; set; } 
    public int NumberTwo { get; set; } 
} 

public class TestClass 
{ 
    public void Test1() 
    { 
     Class12 z = new Class12(); 
     EitherInterface.DoSomething<Class12>((I1)z); 
     EitherInterface.DoSomething<Class12>((I2)z); 
    } 
} 

sản lượng đầu ra này:

I1 : 0 
I2 : 0 

này đáp ứng mục tiêu của lộ một phương pháp duy nhất tên cho người gọi nhưng không giúp bạn vì bạn không sử dụng thông số.

+0

Tôi có thể làm điều đó nhưng tôi sẽ phải viết một thực hiện cho mỗi Giao diện. Đó là lý do tại sao tôi muốn sử dụng Generics ngay từ đầu. – Tobias