2017-08-14 123 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); 
    } 
}