我们真的需要具有类型约束的泛型类吗?

时间:2016-10-05 09:14:32

标签: c# generics

很抱歉,问题的标题有点模糊。
假设我们有以下代码

class ReportManager<T> where T : IPrint
{
    public void MakePaperCopy(T t)
    {
        //...
        t.Print();
        //...
    }
}

public interface IPrint
{
    void Print();
}

可以轻松地重新制作非通用版本。喜欢这个

class ReportManager
{
    public void MakePaperCopy(IPrint print)
    {
        //...
        print.Print();
        //...
    }
}

在第一种情况下是否有一些优势?似乎没有。
我是否可以说每个使用单where T: ISomeInterface的通用类都可以轻松地重新制作为非通用版本,应该这样做,因为它会降低代码的复杂性?

4 个答案:

答案 0 :(得分:5)

在所有情况下都没用 如果您想要返回此T,那么您可能想知道确切的类型 因为当您返回它时,您可以从派生类访问所有(可访问的)成员,而不仅仅是来自基类/接口的成员。

答案 1 :(得分:4)

首先,泛型可以避免很多演员表演。这可以最终在密集型应用程序和服务中获得显着的性能提升。

其次,泛型类型参数接受IPrint(非泛型)的任何实现,而不是整个类型将处理被强制实现的对象IPrint(泛型)的定义不同。

尝试在没有泛型的情况下处理以下类型要求:

  • 我希望TIPrint并继承PrintablePaper

如果没有泛型,遗憾的是,这将使用反射来实现:

// Ugly as hell. And error prone, because it's verified during
// run-time...
if(typeof(IPrint).IsAssignableFrom(typeof(T)) && typeof(T).IsSubclassOf(typeof(PrintablePaper)) 
{
}

使用泛型:T : PrintablePaper, IPrint并尝试将错误的类型作为泛型参数,编译器会说:在你的脸上拍打,拍打你的脸,......

基本上,就高级编程而言,引入了泛型来强制执行强类型在C#中的更多。通用约束提供了编译时可接受的泛型参数的详细信息。也就是说,泛型是根据通用约束定义的规范关闭软件架构/设计以增长的好方法。

关于整个存储库示例,如果您的报表管理员永远不需要处理IPrint的特化,那么泛型在该特定情况下是无用的:接受IPrint类型的强制执行在您的情况下,实施IPrint 几乎相同。

在您的情况下,如果您需要继承该类,那将非常有用:

class ReportManager<T> where T : IPrint
{
    public void MakePaperCopy(T t)
    {
        //...
        t.Print();
        //...
    }
}

class SpecializedReportManager : ReportManager<FancyReport>
{
    // Beat this without generics!!
    // In inherited classes, you can work with the IReport
    // implementation directly and without casts!
    public void MakePaperCopy(FancyReport t)
    {
        //...
        t.Print();
        //...
    }
}

答案 2 :(得分:2)

在值类型的情况下,通用表单将阻止装箱。

此外,您可以让T实现多个接口:

class ReportManager<T> where T : IPrint, IConvertible, IAnotherInterface

第二种形式在这种情况下显然不起作用。

答案 3 :(得分:0)

评论romain-aga之后的帖子 - 还有另一个原因,除了其他人所说的。如果你有一个引用通用接口的约束(比如说where T : IComparable<T>),你就不能将它重新制作成非通用版本。