【问题标题】:C# Generics and polymorphism: an oxymoron?C# 泛型和多态性:矛盾吗?
【发布时间】:2010-12-21 08:29:08
【问题描述】:

我只是想确认一下我对 C# 中的泛型的理解。这已经出现在我工作过的几个代码库中,其中通用基类用于创建类型安全的派生实例。我所说的一个非常简单的例子,

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

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

当我想以多态方式使用派生实例时,问题就出现了。

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

似乎一旦将 Generic 引入到继承层次结构或接口中,您就不能再以多态方式使用该类族,除非它可能是其内部的。这是真的吗?

【问题讨论】:

  • 在我看来 SomeClass 是 DeriveFrom 的基类,而不是 SomeClass,您似乎认为它应该是这样。

标签: c# generics polymorphism


【解决方案1】:

我更喜欢使用抽象类作为所有泛型类型的基础。

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

【讨论】:

  • 不知道尼克提到的“工厂”的实现。但我很确定,它可以很好地在抽象的非泛型“SomeClass”中实现。
  • @Amby 但是如果抽象 void SomeMethod() 的返回类型为 T 且参数类型为 T ,你会怎么做?然后你不能隐藏你的非泛型抽象类下的泛型。我会很感激你的回答或提示:)
  • @Elisabeth 很多时间过去了,但是,您找到解决这种方法的方法了吗?我现在正在处理同样的问题。
  • @Servadac op 尝试使用多态性的原因是有一些独立于类型参数的通用功能,这要求必须有一个带有签名无效类型参数的“SomeMethod”。
【解决方案2】:
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 } ;
    }
}

【讨论】:

  • 以上是泛型多态性如何真正有用的示例。
【解决方案3】:

似乎一旦将泛型引入到继承层次结构或接口中,就不能再以多态方式使用该类族

没错,和这种情况很相似:

class StringContainer
{
}

class IntContainer
{
}

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

但你可以这样做:

class Container
{
}

class Container<T> : Container
{
}

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

【讨论】:

    【解决方案4】:

    我认为您正在寻找的是:

     SomeClass(of someType) someInstance = factory(of someType).Create();
    或许
      SomeClass(of someType) someInstance = factory.Create(of someType)();
    要么
      SomeClass(of someType) someInstance = factory.Create();
    

    可以有一组工厂类来创建不同的泛型类,或者有一个带有泛型类型参数的工厂来指示它应该创建哪个泛型类型(请注意,在任何一种情况下,类型参数都是类型参数对于泛型类,而不是泛型类本身)。也可以有一个工厂,旨在返回泛型类型的一种特定形式的实例。

    【讨论】:

      【解决方案5】:

      我认为您误解了泛型的意义。泛型允许您泛化需要类型的类,但并不特别关心它是什么类型。例如,List&lt;string&gt; 是一个字符串列表,但 List 是什么呢?没有清单是一个相当无用的概念。

      每个专门的类(即List&lt;string&gt;)都是它自己独特的类型,编译器会这样对待它。 可能获取泛型类型本身(例如typeof(List&lt;&gt;)),但在大多数情况下它是无用的,而且您当然不能创建它的实例。

      【讨论】:

        【解决方案6】:

        据我所知,使用代码不需要泛型类的细节(即,它不取决于 T 是什么)。那么,为什么不引入SomeClass&lt;T&gt; 将实现的接口,并使用该接口的实例。

        例如:

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

        现在,SomeClass&lt;T&gt; 的子类可以在不同的Ts 上进行不同的操作,但使用代码不会改变。

        【讨论】:

        • 我认为这是最好的解决方案。我们只扩展客户关心的接口,并将泛型隐藏在底层。
        猜你喜欢
        • 1970-01-01
        • 2021-07-13
        • 2017-11-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-09
        • 2020-12-31
        • 1970-01-01
        相关资源
        最近更新 更多