2017-08-14 128 views
0

爲什麼不能像這樣使用泛型?聲明共同開型或接口和獨立的邏輯,用於直接在每個具體類型:C#泛型類型的多態性

interface IOpen<T> 
{ 
    T A { get; } 
} 

class Concrete<int> : IOpen<int> 
{ 
    public int A => 42; 
    public string B => "42"; 
} 

interface IWorker<T> 
{ 
    void Do(IOpen<T> item); 
} 

class WorkerInt : IWorker<int> 
{ 
    public void Do(Concrete<int> item) 
    { 
     Console.WriteLine(item.A); 
     Console.WriteLine(item.B); 
    } 
} 

如何避免在上面的代碼,限制?如果我創建了ConcreteInt : IOpen<int>類,那麼WorkerInt不會實現IWorker<T>。謝謝。

回答

1

不能定義class Concrete<int><int> - 就像你想覆蓋的int正常定義一個名爲int一個新的通用型。但是,在課堂上,你正試圖返回一個int

因此,它應該是這樣的:

class Concrete : IOpen<int> 
{ 
    public int A => 42; 
    public string B => "42"; 
} 

但現在的類WorkerInt必須是這樣的:

class WorkerInt : IWorker<int> 
{ 
    public void Do(Concrete item) 
    { 
     Console.WriteLine(item.A); 
     Console.WriteLine(item.B); 
    } 
} 

IWorker<int>必須實現void Do(IOpen<T> item)而且即使Concrete器具IOpen<T>你可以」 t使用void Do(Concrete item),因爲它比void Do(IOpen<T> item)更具限制性。

所以,你必須定義它是這樣的:

class WorkerInt : IWorker<int> 
{ 
    public void Do(IOpen<int> item) 
    { 
     Console.WriteLine(item.A); 
     //Console.WriteLine(item.B); 
    } 
} 

但是,讓item.B不再爲IOpen<int>工作沒有B財產。

,使這項工作的唯一方法是改變IWorker是這樣的:

interface IWorker<T, R> where T : IOpen<R> 
{ 
    void Do(T item); 
} 

然後WorkerInt可以這樣:

class WorkerInt : IWorker<Concrete, int> 
{ 
    public void Do(Concrete item) 
    { 
     Console.WriteLine(item.A); 
     Console.WriteLine(item.B); 
    } 
} 
+0

'接口IWorker 其中T:IOPEN '看起來像一個魔術技巧,它沒有嚴重的代碼更改。謝謝。 – Feofilakt

0

泛型不是作爲類型推斷的佔位符。泛型旨在允許像List,DictionaryTree等容器包含任何類型,而不需要向Object投射。他們使容器更加靜態健壯。

如果您希望能夠將有限的一組類型傳遞給某種處理器,請使用重載的方法。

public void Do(int item) { ... } 

public void Do(string item) { ... } 

這種方式,方法的簽名是什麼決定使用哪種方法。

此外,如果您嘗試製作不同的工作對象,則可能會有一組類似的靜態重載方法來實例化工作人員並調用Do()方法。

class WorkerManager { 
    public static void DoWork(int item) { 
     var worker = new WorkerInt(); 
     worker.Do(item); 
    } 

    public static void DoWork(string item) { 
     var worker = new WorkerString(); 
     worker.Do(item); 
    } 
}