什么时候适合使用泛型与继承?

时间:2009-04-28 18:56:03

标签: c# .net vb.net generics inheritance

使用泛型而不是继承有什么情况及其相关的好处,反之亦然,它们应该如何最好地结合起来?

感谢答案的人。

我将尽力说明这个问题的动机: 我有一个课程如下所示:

class InformationReturn<T> where T : Info
{
    InformationReturn(Employee employee, List<T>) { ... }
}

现在假设我有一个采用InformationReturn参数的存储库,它必须根据Info对象T的类型在数据库中编写不同的字段。为T类型创建不同的存储库是否更好;一个使用反射来确定类型的存储库;还是有更好的方法使用继承功能/使用泛型?

注意:其他客户端代码也必须根据T的类型进行不同的操作。

7 个答案:

答案 0 :(得分:12)

泛型和继承是两个不同的东西。继承是一种OOP概念,泛型是一种CLR功能,允许您在编译时为公开它们的类型指定类型参数。

继承和泛型实际上可以很好地协同工作。

<强>继承:

继承允许我创建一个类型:

class Pen { }

然后创建另一个扩展Pen的类型:

class FountainPen : Pen { }

这很有用,因为我可以重用基类的所有状态和行为,并在FountainPen中公开任何新的行为或状态。继承允许我快速创建现有类型的更具体版本。

<强>泛型:

泛型是一个CLR功能,让我创建一个这样的类型:

class Foo<T> 
{
    public T Bar { get; set; }
}

现在,当我使用Foo<T>时,我可以通过提供泛型类型参数来指定T的类型:

Foo<int> foo = new Foo<int>();

现在,由于我已经为我刚创建的对象指定Tint,因此Foo.Bar的类型也将是int声明类型为T

答案 1 :(得分:9)

使用泛型来指定算法或类型的行为,这些行为可以用某种“未知类型”表示,同时保留根据该未知类型强类型的API。未知类型称为类型参数,并在代码中表示如下:

public class List<T>
{
    public void Add(T item)
}

(etc) - 这里T是类型参数。通用方法类似:

public void Foo<T>(T item)

调用代码指定它想要使用的类型参数,例如

List<string> list = new List<string>();
list.Add("hi");

使用继承来专门化类型的行为。

我真的不能想到很多地方都是彼此的替代品......

答案 2 :(得分:8)

我认为当你只想要应用于各种类型(Add,Remove,Count)的相同功能时,你应该使用泛型,并且它将以相同的方式实现。继承是指您需要相同的功能(GetResponse),但希望以不同的方式实现它。

答案 3 :(得分:5)

他们完全是不同的想法。泛型允许您以一般方式声明常见的“特定”功能(冒着发出反应的风险)。 List<int>List<string>的作用不同,除了内部数据类型。

虽然继承可以用来做同样的事情,但我可以创建一个List类,然后创建一个继承自它的IntListStringList类。我可以很容易地使这两个类的功能完全不同,或者在另一个类中提供一个不可用的功能。

修改

在查看问题的编辑后,答案排序是“它取决于”。您可以为双方制作参数 - 事实上,LINQ to SQL和实体框架都是使用泛型的反射检查和强类型实体类以及其他存储库类的组合。你当然可以采用你所看到的方法,只要知道,一般来说,一个可以通过反射或其他东西解决的问题,当被“别的东西”解决时,它会变得更快。它取决于您在性能,可维护性,可读性和可靠性方面需要多少权衡。

答案 4 :(得分:4)

如果要创建可应用于许多未知类样式的“模板”,请使用泛型。例如。藏品???非常适合仿制药。继承是指当你有一个基础锥形图时,孩子“是”这个概念的扩展。

我的一般规则

  • 如果你开始在你的代码中定义适当的Object作为对象并输入很多内容,那么它可能是泛型的时间。
  • 如果你想对“更高概念”以及派生类进行编程,那么它的继承。
  • 如果你的课程要包括或在一个音乐会课程上工作,那么它的泛型。
  • 如果你依赖于一个未知的“未定义”类的细节,那么你可能更好地使用泛型。
  • 如果派生类是“is a”,那么它通常是继承
  • 如果你的超类“使用了一些x”,那么它的泛型。

答案 5 :(得分:3)

继承更多地是关于“is-a”(青蛙是一种动物),其中泛型是关于创建作用于类型数据的容器(T的列表,T的处理器等)。它们不相互排斥

如果您愿意,可以这样做:

public class Base<T>
{

}

public class Derived : Base<Foo>
{

}

答案 6 :(得分:0)

继承和参数化类型都不能在运行时更改

继承可让您提供操作的默认实现,并让子类覆盖它们。

参数化类型使您可以更改类可以使用的类型。

但是哪种方法最好取决于您的设计和实现约束

  

可重用的面向对象软件的设计模式元素