很抱歉,问题的标题有点模糊。
假设我们有以下代码
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
的通用类都可以轻松地重新制作为非通用版本,应该这样做,因为它会降低代码的复杂性?
答案 0 :(得分:5)
在所有情况下都没用
如果您想要返回此T
,那么您可能想知道确切的类型
因为当您返回它时,您可以从派生类访问所有(可访问的)成员,而不仅仅是来自基类/接口的成员。
答案 1 :(得分:4)
首先,泛型可以避免很多演员表演。这可以最终在密集型应用程序和服务中获得显着的性能提升。
其次,泛型类型参数接受IPrint
(非泛型)的任何实现,而不是整个类型将处理被强制实现的对象IPrint
(泛型)的定义不同。
尝试在没有泛型的情况下处理以下类型要求:
T
为IPrint
并继承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>
),你就不能将它重新制作成非通用版本。