2013-11-14 13 views
5

Tôi sẽ cho các mã làm như nói chuyện:Không thể thêm một trường hợp cụ thể của một giao diện chung để một bộ sưu tập chung

using System.Collections.Generic; 

namespace test 
{ 
    public interface IThing { } // can't change this - it's a 3rd party thing 

    public interface IThingRepository<T> where T : class, IThing { } // can't change this - it's a 3rd party thing 

    public interface IThingServiceInstance<T> 
     where T : class, IThing 
    { 
     IThingRepository<T> Repository { get; set; } 
    } 

    public class ThingServiceInstance<T> : IThingServiceInstance<T> where T : class, IThing 
    { 
     public IThingRepository<T> Repository { get; set; } 

    } 

    public class MyThing : IThing 
    { 
    } 

    class Test 
    { 
     public void DoStuff() 
     { 
      IList<IThingServiceInstance<IThing>> thingServiceInstances = new List<IThingServiceInstance<IThing>>(); 
      // the following line does not compile. Errors are: 
      // 1: The best overloaded method match for 'System.Collections.Generic.ICollection<test.IThingServiceInstance<test.IThing>>.Add(test.IThingServiceInstance<test.IThing>)' has some invalid arguments C:\TFS\FACE\ResearchArea\ArgonServiceBusSpike\Argon_Service_Bus_Spike_v2\Argon.ServiceLayer\test.cs 31 13 Argon.ServiceGateway 
      // 2: Argument 1: cannot convert from 'test.ThingServiceInstance<test.MyThing>' to 'test.IThingServiceInstance<test.IThing>' C:\TFS\FACE\ResearchArea\ArgonServiceBusSpike\Argon_Service_Bus_Spike_v2\Argon.ServiceLayer\test.cs 31 39 Argon.ServiceGateway 
      // Why? ThingServiceInstance is an IThingServiceInstance and MyThing is an IThing 
      thingServiceInstances.Add(new ThingServiceInstance<MyThing>()); 
     } 
    } 
} 

Nếu ThingServiceInstance là một IThingServiceInstanceMyThing là một IThing, tại sao có thể không Tôi thêm một ThingServiceInstance<MyThing> vào bộ sưu tập của IThingServiceInstance<IThing>?

Tôi có thể làm gì để biên dịch mã này?

+0

[Hiệp phương sai và Contravariance trong Generics] (http://msdn.microsoft.com/en-us/library/dd799517 (v = vs.110).aspx) – Jehof

+0

Tìm kiếm với từ khóa "Hiệp phương sai và đối nghịch" –

Trả lời

3

ThingServiceInstance<MyThing>KHÔNG một subtype của IThingServiceInstance<IMyThing>, vì IThingServiceInstance<T>bất biến trong tham số kiểu của nó <T>.

Nếu bạn muốn thực hiện ThingServiceInstance<MyThing> một loại phụ của IThingServiceInstance<IMyThing>, thì T phải là biến thể. Trong C#, bạn làm điều đó bằng cách tuyên bố IThingServiceInstance<T> như vậy:

public interface IThingServiceInstance<out T> 

Sửa này, tuy nhiên ngụ ý rằng ThingServiceInstance<T> chỉ có thể trở lại trường hợp của T, nhưng không bao giờ có họ như các đối số phương pháp (vì thế "out" ký hiệu).

Edit2

Đây là ý chính của lý do tại sao mã của bạn đã không được biên dịch. Như đã chỉ ra, vì ThingServiceInstance<T> của bạn cho thấy một tài sản IThingRepository<T>, mà cũng đã được hiệp biến như vậy:

public interface IThingRepository<out T> where T : class, IThing { } 

như sau, bất động sản của bạn phải có được chỉ (hãy nhớ, bạn chỉ có thể trở trường hợp T hoặc U<T> cho vấn đề đó).

+0

Bạn cần phải thay đổi cả hai giao diện để có biến thể 'T'. Khi nó đứng, thay đổi của bạn không biên dịch với 'Phương sai không hợp lệ: Tham số kiểu 'T' phải có giá trị bất biến hợp lệ trên 'IThingServiceInstance .Repository'. 'T' là covariant.' – Rob

+0

Đúng vậy, tôi đã cập nhật câu trả lời của mình. – dcastro

1

Bạn có thể làm cho nó biên dịch nếu bạn khai báo hai biến thể giao diện và loại bỏ bộ đặt từ IThingServiceInstance.

Tất nhiên, bạn không thể thay đổi giao diện của bên thứ ba, vì vậy điều này không thực sự hữu ích.

public interface IThingRepository<out T> where T : class, IThing { } // can't change this - it's a 3rd party thing 

public interface IThingServiceInstance<out T> 
    where T : class, IThing 
{ 
    IThingRepository<T> Repository { get; } 
} 

Nếu IThingRepository<T> không tuyên bố T hiệp biến, sau đó cho

T : A 

bạn không nhận được

IThingRepository<T> : IThingRespository<A> 

và do đó bạn không thể có

IThingServiceInstance<T> : IThingServiceInstance<A> 

vì loại được trả về bởi bộ thu không phải là "tương thích".

+1

Đó là "covariant", không phải "contravariant". Ngoài ra, bạn không cần phải gỡ bỏ setter. –

+0

@D Stanley: Nếu tôi rời khỏi setter, tôi nhận được một lỗi biên dịch: 'Phương sai không hợp lệ: Tham số kiểu 'T' phải có giá trị tương đối hợp lệ trên 'IThingServiceInstance .Repository'. 'T' là biến thể. ' – Rob

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