【问题标题】:When is it Appropriate to use Generics Versus Inheritance?什么时候使用泛型与继承比较合适?
【发布时间】:2010-10-22 09:53:10
【问题描述】:

在什么情况下使用泛型而不是继承,反之亦然,它们的最佳组合方式是什么?

谢谢大家的回答。

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

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

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

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

【问题讨论】:

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


    【解决方案1】:

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

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

    继承:

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

    class Pen { }
    

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

    class FountainPen : Pen { }
    

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

    泛型:

    泛型是一个 CLR 特性,它让我可以创建这样的类型:

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

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

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

    现在,因为我已经指定 T 应该是我刚刚创建的对象的 int,所以 Foo.Bar 的类型也将是 int,因为它被声明为 T 类型。

    【讨论】:

    • 但是你应该什么时候使用它们呢?
    • 学究式的挑剔:您提供了一个泛型类型 argument,即 T 是类型参数,int 是类型参数。我会让你决定是否值得编辑:)
    • 已修复!感谢您指出这一点,迂腐永远不会不受欢迎 - 天知道我自己处理了很多:)
    • 感谢您的快速回复。我已经修改了问题,以便更清楚地说明我提出问题的动机。
    【解决方案2】:

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

    如果你愿意,你可以拥有这个:

    public class Base<T>
    {
    
    }
    
    public class Derived : Base<Foo>
    {
    
    }
    

    【讨论】:

    • 而且其实可以有泛型接口:public interface IBase -> public abstract Base : IBase -> public class Derived : Base
    【解决方案3】:

    它们是完全不同的想法。泛型允许您以一般方式声明常见的“特定”功能(冒着听起来矛盾的风险)。 List&lt;int&gt;List&lt;string&gt; 的功能没有任何不同,除了内部保存的数据类型。

    虽然可以使用继承来做同样的事情,但我可以创建一个 List 类,然后创建一个 IntList 和一个从它继承的 StringList 类。我可以轻松地使这两个类的功能完全不同,或者让一个提供的功能在另一个中不可用。

    编辑

    查看问题的编辑后,答案是“视情况而定”。您可以为双方提出论据——事实上,LINQ to SQL 和实体框架都是使用泛型的反射检查、强类型实体类和其他存储库类的组合。您当然可以采用您正在研究的方法,只要知道,一般来说,可以通过反射或其他方式解决的问题在通过“其他方式”解决时可能会更快。这取决于您希望在性能、可维护性、可读性和可靠性之间做出多大的权衡。

    【讨论】:

    • 这个答案帮助我指出当行为和继承没有区别时我应该使用泛型,谢谢。我已经修改了这个问题,以便更清楚地了解我的动机。
    【解决方案4】:

    当您只希望将相同的功能应用于各种类型(添加、删除、计数)并且它将以相同的方式实现时,您应该使用泛型。继承是指您需要相同的功能 (GetResponse) 但希望它以不同的方式实现

    【讨论】:

    • IMO,这实际上是这个问题的最佳答案!搜索 SE 大约 20 分钟后..
    【解决方案5】:

    使用泛型来指定一种算法或类型的行为,这些行为可以用某种“未知类型”来表达,同时保持一个用该未知类型强类型化的 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");
    

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

    我真的想不出有多少地方可以相互替代......

    【讨论】:

    • 虽然我没有对你投反对票,但你的回答有点没用。 OP 显然是 .NET 的新手,您极其简短的字典定义可能对消除他/她的任何困惑几乎没有帮助。
    • 感谢您的回复,您能否澄清一下您所说的“以某种“未知类型”表示时的意思?另外,我已经修改了问题,以便更清楚地了解我提出问题的上下文。
    【解决方案6】:

    当您想创建一个可以应用于许多未知类样式的“模板”时,请使用泛型。例如。收藏夹???是仿制药的良好候选者。继承适用于当您有一个基本概念时,孩子“是”该概念的扩展。

    我的一般规则

    • 如果您开始在代码中将属性定义为 Object 并进行大量类型转换,那么可能是泛型的时候了。
    • 如果您想针对“更高的概念”以及派生类进行编程,那么它的继承。
    • 如果您的类要包装或处理一个一致的类,那么它的泛型。
    • 如果您依赖于未知“尚未定义”类的细节,那么使用泛型可能会更好。
    • 如果你的派生类是“is a”那么它通常是继承
    • 如果您的超类“使用一些 x”,那么它的泛型。

    【讨论】:

      【解决方案7】:

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

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

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

      但哪种方法最好取决于您的设计和实现限制

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-02-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-06
        • 1970-01-01
        • 2021-12-12
        相关资源
        最近更新 更多