“在大多数情况下,基础抽象通用类是一个糟糕的选择。”为什么? (或者为什么不)

我刚看到博客文章的评论:

在大多数情况下,基本抽象generics类是一个糟糕的选择

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

有什么见解导致这种说法?

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

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

// Meaningful common ancestor for the working classes. interface IWorker { object DoWork(); } // Generic abstract base class for working classes implementations. abstract WorkerImpl : IWorker { public abstract TResult DoWork(); object IWorker.DoWork() { return DoWork(); // calls TResult DoWork(); } } // Concrete working class, specialized to deal with decimals. class ComputationWorker : WorkerImpl { override decimal DoWork() { decimal res; // Do lengthy stuff... return res; } } 

在此示例中, DoWork()在抽象类中重新定义,在ComputationWorker变得具体和专业。

我同意,因为任何inheritance抽象generics类的东西都不会与基类一致。 也就是说,如果你有

abstract class myBase

然后你创造

 class myThing: myBase class myOtherThing: myBase 

你不能创建适用于myThing和myOtherThing的方法,因为它们不共享祖先。 基类中没有任何意义是抽象的,真的,它也可能只是一个类。

但是如果你有一个基类

 abstract class myBase class myBase: myBase 

作为generics类的常见模式(如IEnumerable – 使用接口),它们都共享myBase。

(编辑)我刚刚阅读了实际的博客文章 – 实际上,评论在那种情况下并不真正有效。 他指的是“抽象通用基类”, Rangeinheritance了IEnumerable ,它inheritance了非通用接口IEnumerable 。 所以它并不是一个“抽象的通用基类”。 但一般来说我认为这是真的。

抽象通用基类的一个问题是你不能输入decorate:

 public abstract class Activity { public Activity() { } protected virtual object Implementation { ... } } public abstract class CompensableActivity : Activity where TCompensation : Activity, new() { public CompensableActivity() { } protected override object Implementation { get { new Wrapper(base.Implementation, Compensation); } } private Activity Compensation { get { var compensation = new TCompensation(); if(compensation is CompensableActivity) { // Activity "does not meet new() constraint" ! var compensable = comp as CompensableActivity>; var implement = compensable.Implementation as Wrapper; return implement.NormalActivity; } else { return compensation; } } } } 

克拉根说得好。 任何低于你代码50%的东西都是“大多数情况下的错误选择”。

但是,即使你的类中有近50%的类应该是通用的抽象基类,它也不比其他任何语言特性好。

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

KeyedCollection不仅仅是一个抽象的通用基类,它只是一个。 要使用它,你必须从它派生并实现GetKeyForItem

我不同意这里的人群。 在某些情况下,抽象generics类是最好的设计。 .NET中的一个很好的例子可以在System.Collections.ObjectModel中找到,其中KeyedCollection允许您轻松覆盖和实现类型化的可序列化字典集合!

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

 public class NameCollection : System.Collections.ObjectModel.KeyedCollection { protected override string GetKeyForItem(INamedObj item) { return item.Name; } } 

好吧,从统计学上讲,如果有人问我应该把这个class级变成一个抽象的通用类吗?” 答案几乎可以肯定是 – 在3年的.Net开发中我认为我可以计算我编写的具有generics类型参数的抽象类的数量。

除此之外,我看不出抽象generics类被认为是坏事的任何特殊原因 – 它只是不常见。

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

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

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

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

我想我想说的是这一切都取决于背景及其实际使用方式。