【问题标题】:Type Parameter Constraint is a Class类型参数约束是一个类
【发布时间】:2012-04-23 12:57:17
【问题描述】:

我注意到其他开发人员使用这种技术,但它总是让我感到困惑。今天早上我决定调查一下,在 MSDN 上发现了以下内容(来自http://msdn.microsoft.com/en-us/library/d5x73970(v=vs.100).aspx):

public class GenericList<T> where T : Employee
{
...
}

为什么我们要使用这个方法而不是用 Employee 替换类中的所有 T 实例?对我来说,这似乎是可维护性的胜利。我可以将限制接口理解为包含来自不同继承层次结构的类的一种方式,但是继承已经以更明显的方式解决了上述问题,不是吗?

这会被认为是一个错误,还是像这样“修复”代码是一个错误?

【问题讨论】:

  • 虽然现在这对我来说很有意义,但我认为我仍然看到当非泛型方法更合适时使用这种方法,这可能使我对更可接受的用途的愿景模糊。
  • @sprague:你能举个例子吗?最好来自库?
  • @Henk Holterman:可以说在某些情况下类型参数是多余的。在这种情况下,我最感兴趣的是在其约束中具有特定类的类型参数的有效情况。在我了解这种用途的情况之前,我不想对情况做出判断(感谢您和其他人,我现在知道了。)

标签: c# generics inheritance interface covariance


【解决方案1】:

因为它可能是从 Employee 派生的。

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 替换为约束类型。类本身不介意用约束类型代替泛型,但如果它有任何提到的返回或参数类型,那么想要使用派生类型的类的代码就会有问题。
【解决方案2】:

为什么我们要使用这个方法而不是用 Employee 替换类中的所有 T 实例?

启用:

class Manager : Employee { ... }

var board = new GenericList<Manager> ();

请注意,在这种情况下,您的名称“GenericList”更像是“EmployeeList”

我可以理解将接口限制为包含来自不同继承层次结构的类的一种方式

类继承和接口有很多共同点。

但是继承已经以更明显的方式解决了上述问题,不是吗?

是的,但不一样。 board.Add(lowlyProgrammer); 将在此处失败,而继承将允许它。

【讨论】:

  • 经理已经是一名员工了,这已经可以通过多态实现......我错过了什么吗?
  • @Sprague: board.Add(lowlyProgrammer); 在这里会失败。
  • +1 简洁 - 一种在泛型上强制执行类型层次结构安全的简单方法,同时保持输入/输出类型(例如添加/获取方法)等于类型 T;如果它是非泛型的,则简化调用者的使用。
  • 感谢您的回答,不过,Simon 立即向我说明了这一点。 + 表示速度。
【解决方案3】:

故意添加Where语句。想想有从 Employee 类派生的类的情况;如果不定义泛型类,则需要为每个派生类定义一个类。

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

【讨论】:

    【解决方案4】:

    泛型允许您在无需强制转换的情况下实现类型安全。

    如果你有

      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();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多