C# &引用;在大多数情况下,基本抽象泛型类是一个错误的选择。”;为什么?(或者为什么不)

C# &引用;在大多数情况下,基本抽象泛型类是一个错误的选择。”;为什么?(或者为什么不),c#,.net,generics,inheritance,C#,.net,Generics,Inheritance,我刚刚在一篇帖子的评论中看到: 基本抽象泛型类是一个坏的 大多数情况下的选择 这是真的吗?如果不是,为什么 什么洞察导致了这种说法?我同意,因为任何继承抽象泛型类的东西都不会与基类多态。也就是说,如果你有 抽象类myBase 然后你创造 class myThing: myBase<thing> class myOtherThing: myBase<otherThing> 类神话:myBase 类myOtherThing:myBase 您不能创建与神话和myOtherT

我刚刚在一篇帖子的评论中看到:

基本抽象泛型类是一个坏的 大多数情况下的选择

这是真的吗?如果不是,为什么


什么洞察导致了这种说法?

我同意,因为任何继承抽象泛型类的东西都不会与基类多态。也就是说,如果你有

抽象类myBase

然后你创造

class myThing: myBase<thing>
class myOtherThing: myBase<otherThing>
类神话:myBase
类myOtherThing:myBase
您不能创建与神话和myOtherThing相反的方法,因为它们不共享祖先。基类是抽象的没有意义,实际上,它也可能只是一个类

但是如果你有一个基类

abstract class myBase
class myBase<T>: myBase
抽象类myBase
类myBase:myBase
与泛型类(如使用IEnumerable的接口)的常见模式一样,它们都共享myBase


(编辑)我刚刚读了一篇真实的博客文章——事实上,在这种情况下,评论并不真正有效。他所指的“抽象泛型基类,
Range
继承了
IEnumerable
,它继承了非泛型接口
IEnumerable
。所以它并不是一个真正的“抽象泛型基类”。但通常我认为它是正确的。

在某些情况下,抽象基类是有用的

我们有几个使用不同数据库引擎的.net应用程序。几个sql server、几个mysql和一些oracle应用程序

我们有一个通用的公共数据库对象,它基于一个抽象类,这个抽象类是一个工厂,它根据数据库的类型在工厂设置中返回正确的数据库对象

这样,如果我要启动一个新的应用程序,我所要做的就是加载这个数据库对象,传入类型,传入连接字符串,然后bam。。。我准备好了


我想我想说的是,这完全取决于上下文及其实际使用方式。

好吧,从统计学上讲,如果有人问我“我应该把这个类设置为抽象泛型类吗?”,答案几乎肯定是否定的——在.Net开发的3年时间里,我想我一方面可以计算出我编写的具有泛型类型参数的抽象类的数量


除此之外,我看不出有什么特别的理由认为抽象泛型类是一件坏事——它并不那么常见。

Kragen提出了一个很好的观点。任何少于代码50%的内容都是“在大多数情况下的错误选择”

然而,即使您的类中有50%应该是泛型抽象基类,但它也不亚于任何其他语言特性

例如,
BindingList
可以被认为是一个抽象的泛型基类。它是一个通用容器,排序要求您从中派生并重写
ApplySortCore

KeyedCollection
不仅仅像一个抽象的泛型基类,它还是一个。要使用它,您必须从中派生并实现
GetKeyForItem

“大多数情况”是完全模糊的。如果通用抽象类(或接口)的后代之间唯一的共同祖先是System.Object(如本问题的其他评论者所指出的),那么使用通用抽象类(或接口)是个坏主意

否则(例如,如果您确实有一个有意义的共同祖先),如果您想“重命名”或“专门化”成员,这是一个好主意。考虑这个例子:

// Meaningful common ancestor for the working classes.
interface IWorker
{
   object DoWork();
}

// Generic abstract base class for working classes implementations.
abstract WorkerImpl<TResult> : IWorker
{
   public abstract TResult DoWork();

   object IWorker.DoWork()
   {
      return DoWork(); // calls TResult DoWork();
   }
}

// Concrete working class, specialized to deal with decimals.
class ComputationWorker : WorkerImpl<decimal>
{
    override decimal DoWork()
    {
       decimal res;

       // Do lengthy stuff...

       return res;
    }
}
//工作类的有意义的共同祖先。
接口IWorker
{
对象DoWork();
}
//用于工作类实现的通用抽象基类。
抽象工作示例:IWorker
{
公共摘要TResult DoWork();
对象IWorker.DoWork()
{
return DoWork();//调用TResult DoWork();
}
}
//具体的工人阶级,专门处理小数。
类计算工作者:WorkerImpl
{
重写十进制DoWork()
{
十进制分辨率;
//做冗长的事情。。。
返回res;
}
}

在这个例子中,
DoWork()
在抽象类中被重新定义,在
ComputationWorker
中变得具体和专业化,我不同意这里的观点。在某些情况下,抽象泛型类是最佳设计。 NET中的一个很好的例子可以在System.Collections.ObjectModel中找到,其中KeyedCollection允许您轻松重写和实现类型化的可序列化字典集合

我省略了大部分代码,但这是原则:

public class NameCollection : System.Collections.ObjectModel.KeyedCollection<string, INamedObj>
{

    protected override string GetKeyForItem(INamedObj item)
    {
        return item.Name;
    }
}
公共类名称集合:System.Collections.ObjectModel.KeyedCollection
{
受保护的重写字符串GetKeyForItem(INamedObj项)
{
返回项目名称;
}
}

抽象泛型基类的一个问题是不能键入修饰:

public abstract class Activity<TEntity>
{
  public Activity() { }

  protected virtual object Implementation { ... }
}

public abstract class CompensableActivity<TEntity,TCompensation> : Activity<TEntity>
  where TCompensation : Activity<T>, new()
{
  public CompensableActivity() { }

  protected override object Implementation
  {
    get { new Wrapper(base.Implementation, Compensation); }
  }

  private Activity<TEntity> Compensation
  {
    get
    {
      var compensation = new TCompensation();
      if(compensation is CompensableActivity<TEntity,Activity<TEntity>)
      {
        // Activity<TEntity> "does not meet new() constraint" !
        var compensable = comp as CompensableActivity<TEntity, Activity<TEntity>>;
        var implement = compensable.Implementation as Wrapper;
        return implement.NormalActivity;
      }
      else { return compensation; }
    }
  }
}
公共抽象类活动
{
公共活动(){}
受保护的虚拟对象实现{…}
}
公共抽象类可补偿性:活动
其中t补偿:活动,新()
{
公共可补偿性(){}
受保护的覆盖对象实现
{
获取{new Wrapper(base.Implementation,Compensation);}
}
私人活动补偿
{
得到
{
var补偿=新的T补偿();

如果(补偿是可补偿的。你可能应该问为什么不问问作者?没有正当理由的随机博客评论与真实情况不一样。在某些情况下,它可能是真实的,而在另一些情况下,则不是。即使是随机博客中的评论,也很有意思,看看用户在这个主题中有何评论。你是指环到协方差,这在.NET4.0中应该是可能的?@Frederik,我认为只有
thing
otherThing
来自同一个类时,这才有意义。+1--“基类没有抽象的意义,实际上,它也可能只是一个类。”