简体   繁体   English

C#泛型和多态:一个矛盾?

[英]C# Generics and polymorphism: an oxymoron?

I just want to confirm what I've understood about Generics in C#. 我只想确认一下我对C#中的泛型的理解。 This has come up in a couple code bases I've worked in where a generic base class is used to create type-safe derived instances. 这已经出现在我使用的几个代码库中,其中使用通用基类来创建类型安全的派生实例。 A very simple example of what I'm talking about, 我正在谈论的一个非常简单的例子,

public class SomeClass<T>
{
    public virtual void SomeMethod(){ }
}

public class DeriveFrom :SomeClass<string>
{
    public override void SomeMethod()
    {
        base.SomeMethod();
    }
}

The problem comes up when I then want to use derived instances in a polymorphic way. 当我想以多态方式使用派生实例时,问题出现了。

public class ClientCode
{
    public void DoSomethingClienty()
    {
        Factory factory = new Factory();
        //Doesn't compile because SomeClass needs a type parameter!
        SomeClass someInstance = factory.Create();

        someInstance.SomeMethod();
    }
}

It seems that once you introduce a Generic into an inheritance hierarchy or interface, you can no longer use that family of classes in a polymorphic way except perhaps internal to itself. 看来,一旦将Generic引入继承层次结构或接口,就不能再以多态方式使用该类族,除非它本身就是内部的。 Is that true? 真的吗?

As far as I can see, consuming code doesn't need specifics of generic class (ie, it doesn't depends on what T is). 据我所知,使用代码不需要泛型类的细节(即,它不取决于T是什么)。 So, why don't you introduce interface that SomeClass<T> will implement, and use instance of this interface. 那么,为什么不介绍SomeClass<T>将实现的接口,并使用该接口的实例。

Eg: 例如:

public interface ISome
{
    void SomeMethod();
}

public class SomeClass<T>: ISome
{
    public virtual void SomeMethod(){ }
}

public void DoSomethingClienty()
{
    Factory factory = new Factory();
    ISome someInstance = factory.Create();

    someInstance.SomeMethod();
}

Now, subclasses of SomeClass<T> can operate differently on different T s, but consuming code won't change. 现在, SomeClass<T>子类可以在不同的T s上以不同的方式运行,但消耗代码不会改变。

I think you are misunderstanding the point of generics. 我认为你误解了仿制药的观点。 Generics allows you to generalise a class that requires a type, but doesn't particularly care itself what type that is. 泛型允许您概括需要类型的类,但不特别关心它是什么类型。 For instance, a List<string> is a list of strings, but what would a List be? 例如, List<string>是一个字符串列表,但List是什么? It's a rather useless concept to have a list of nothing. 拥有一个没有任何列表是一个相当无用的概念。

Each specialised class (ie, List<string> ) is it's own distinct type , and the compiler treats it as such. 每个专用类(即List<string> )都是它自己的不同类型 ,编译器将其视为此类。 It is possible to get at the generic type itself ( typeof(List<>) for instance), but in most cases it's useless, and you certainly can't make an instance of it. 可以获取泛型类型本身(例如typeof(List<>) ),但在大多数情况下它是无用的,你肯定无法创建它的实例。

I would prefer using abstract class to act as base of all generic types. 我更喜欢使用抽象类作为所有泛型类型的基础。

public abstract class SomeClass 
{
    public abstract void SomeMethod();
}

public class SomeClass<T> : SomeClass
{
    public override void SomeMethod() { }            
}

public class DeriveFrom<String> : SomeClass<String>
{
    public override void SomeMethod() { base.SomeMethod(); }            
}

It seems that once you introduce a Generic into an inheritance hierarchy or interface, you can no longer use that family of classes in a polymorphic way 看来,一旦将Generic引入继承层次结构或接口,就不能再以多态方式使用该类族

Correct, it's quite similar to this situation: 正确,它与这种情况非常相似:

class StringContainer
{
}

class IntContainer
{
}

StringContainer container = new IntContainer(); // fails to compile

but you could do this: 但你可以这样做:

class Container
{
}

class Container<T> : Container
{
}

Container container = new Container<String>(); // OK

I think what you're looking for is: 我想你要找的是:

SomeClass(of someType) someInstance = factory(of someType).Create();
or maybe
  SomeClass(of someType) someInstance = factory.Create(of someType)();
or
  SomeClass(of someType) someInstance = factory.Create();

It's possible to have a set of factory classes to create different generic classes, or to have a factory with a generic type parameter to indicate which generic type it should create (note that in either case, the type parameter is the type parameter for the generic class, rather than being the generic class itself). 可以有一组工厂类来创建不同的泛型类,或者让工厂使用泛型类型参数来指示它应该创建哪种泛型类型(请注意,在任何一种情况下,type参数都是泛型的类型参数类,而不是泛型类本身)。 It's also possible to have a factory which is designed to return instances of one particular form of a generic type. 也可以有一个工厂,用于返回一种特定形式的泛型类型的实例。

public Class ReflectionReport<T> 
{
    // This class uses Reflection to produce column-based grids for reporting.  
    // However, you need a type in order to know what the columns are. 
}

... so, in another class you have...

public Class ReflectionReportProject {
    ReflectionReport<Thang> thangReport = new ReflectionReport<Thang>(); 
    ReflectionReport<Thong> thongReport = new ReflectionReport<Thong>(); 



    ... some more stuff ...

    // Now, you want to pass off all of the reports to be processed at one time....
    public ReflectionReport<????>[] ProvideReports() 
    {
        return new ReflectionReport<????>[] { thangReport, thongReport } ;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM