类型参数约束是一个类。

4

我发现其他开发人员使用了这种技术,但它总是让我感到困惑。今天早上我决定调查一下,在MSDN上找到了以下内容:

(来自http://msdn.microsoft.com/en-us/library/d5x73970(v=vs.100).aspx)

这个链接介绍了一个关于IT技术的技巧,但我需要更多的信息才能做出更好的理解。
public class GenericList<T> where T : Employee
{
...
}

为什么我们要使用这种方法,而不是在类中用 Employee 替换所有 T 实例?对我来说,这似乎可以提高可维护性。我能理解将其限制为接口是包括来自不同继承层次的类的一种手段,但是继承已经以一种更明显的方式解决了上述问题,不是吗?
这算是一个错误吗?或者修复这样的代码会是一个错误?

尽管现在我理解这一点,但我认为在非泛型方法更合适的情况下,我仍然看到过使用这种方法的情况,这可能会模糊对更可接受用法的看法。 - Sprague
@sprague:你能给个例子吗?最好是从库里面的。 - H H
足以说,会有一些情况下类型参数是多余的。这是这样一个情况,我主要关注的是类型参数具有特定类约束的有效情况。在了解了这种使用情况后,我不想对此做出评判,感谢您和其他人的帮助。 - Sprague
4个回答

8

因为它可能是从员工衍生出来的东西。

public class EvilEmployee : Employee {
    public Int32 Evilness { get; set; }
}

现在可以使用...

GenericList<EvilEmployee> list = GetEvilEmployees();
var mostEvilEmployee = list.OrderByDescending(e => e.Evilness).First();

由于我们在编译时知道T = EvilEmployee,且EvilEmployee具有Evilness属性,因此这是可能的。如果我们将列表强制转换为Employee的列表,则不可能实现该功能(除非使用OfType)。


放大一下:如果一个带有类约束泛型类型T的类没有返回任何T类型或涉及T类型的方法,没有T类型或涉及T类型的ref/out参数,并且不接受T类型或涉及T类型的消费者,则通常可以将所有T类型的出现替换为约束类型。类本身不介意用约束类型替换泛型类型,但如果它具有任何上述返回或参数类型,则想要使用派生类型与该类一起使用的代码将会遇到问题。 - supercat

5
为什么我们要使用这种方法,而不是在类中替换所有T实例为Employee?
启用:
class Manager : Employee { ... }

var board = new GenericList<Manager> ();

请注意,在这种情况下,您的名称“GenericList”更像是“EmployeeList”。
类继承和接口有很多共同点。
是的,但它们并不相同。在这里,“board.Add(lowlyProgrammer);”将失败,而继承则允许它。

经理已经是一名员工了,这在多态方面已经是可能的了...我有什么遗漏吗? - Sprague
@Sprague:在这里会失败,board.Add(lowlyProgrammer); - H H
1
+1 简洁 - 一种简单的方式,在保持输入/输出类型(例如添加/获取方法)等于类型 T 的同时,对泛型实施类型层次结构安全性的简化,使调用者的使用更加简单。 - Andras Zoltan
谢谢你的回答,Simon立刻让我明白了,而且速度很快。 - Sprague

0

泛型允许您在不需要强制转换的情况下进行类型安全操作。

如果您有

  public class Manager : Employee
  {
     public double CalculateManagerBonus();
  }

你可以做
   GenericList<Manager> managers = ....

   managers[0].CalculateManagerBonus();

如果你有

   GenericList<Employee> managers = ....

   // this is a compiler error
   managers[0].CalculateManagerBonus();

  // this is neccessary if there where no generics.
  ((Manager)managers[0]).CalculateManagerBonus();

0

Where语句是有意添加的。想象一种情况,有些类派生自Employee类;如果您不定义一个通用类,那么您需要为每个派生类定义一个类。

例如,如果EmployeeX继承Employee,并且您想要定义一个仅接受EmployeeX实例的List,通过使用通用方法,您无需定义一个新类。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接