2013-11-14 19 views
5

我讓代碼來說話:不能通用接口的具體實例添加到泛型集合

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>()); 
     } 
    } 
} 

如果ThingServiceInstance是一個IThingServiceInstanceMyThingIThing,爲什麼不能我添加一個ThingServiceInstance<MyThing>到IThingServiceInstance<IThing>的集合?

我能做些什麼來使代碼編譯?

+0

[泛型中的協變和逆變](http://msdn.microsoft.com/en-us/library/dd799517(v = vs.110))。aspx) – Jehof

+0

搜索關鍵字「協方差與反變量」 –

回答

3

ThingServiceInstance<MyThing>NOTIThingServiceInstance<IMyThing>一個亞型,因爲IThingServiceInstance<T>處於其類型參數<T>不變

如果您想使ThingServiceInstance<MyThing>IThingServiceInstance<IMyThing>的子類型,那麼T必須是協變的。 在C#中,你這樣做,通過聲明IThingServiceInstance<T>這樣:

public interface IThingServiceInstance<out T> 

編輯 然而這意味着ThingServiceInstance<T>只能返回的T實例,但從來沒有讓他們的方法參數(因此「走出去」符號)。

EDIT2

這就是爲什麼你的代碼沒有編制的要點。正如指出的那樣,因爲你ThingServiceInstance<T>暴露了IThingRepository<T>屬性時,也有像這樣被協變:

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

如下,你的財產必須是取得只(記住,你只能回報實例TU<T>)。

+0

您需要將兩個接口更改爲具有協變「T」。就目前而言,您的更改不會使用'無效的差異進行編譯:類型參數'T'必須在'IThingServiceInstance .Repository'上始終有效。 'T'是協變的。' – Rob

+0

這是正確的,我已經更新了我的答案。 – dcastro

1

如果聲明兩個接口coariant,則可以將其編譯,並從IThingServiceInstance中刪除setter。

當然,你不能改變第三方接口,所以這並沒有真正的幫助。

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; } 
} 

如果IThingRepository<T>沒有聲明T協變,那麼

T : A 

你沒有得到

IThingRepository<T> : IThingRespository<A> 

,所以你不能有

IThingServiceInstance<T> : IThingServiceInstance<A> 

由於getter返回的類型不是「兼容的」。

+1

這是「協變」,而不是「逆變」。此外,你不需要移除setter。 –

+0

@D Stanley:如果我離開setter,我會得到一個編譯錯誤:'無效的方差:類型參數'T'必須在'IThingServiceInstance .Repository'上反向有效。 'T'是協變的 – Rob

相關問題