我一直在阅读协变和逆变 -维基百科谈到以下内容:
假设你有一个代表一个人的类。一个人可以看医生,所以这个类可能有一个方法 virtual void Person::see(Doctor d)。现在假设您要创建 Person 类 Child 的子类。也就是说,一个孩子就是一个人。然后可能想创建一个子类 Doctor, Pediatrician。如果孩子只看儿科医生,我们希望在类型系统中强制执行。然而,一个简单的实现失败了:因为 Child 是一个 Person,所以 Child::see(d) 必须接受任何医生,而不仅仅是儿科医生。
这是一个“幼稚的实现”:
public interface IDoctor
{
}
public interface IPerson
{
void VisitDoctor(IDoctor doctor);
}
public class Adult : IPerson
{
public void VisitDoctor(IDoctor doctor)
{
Console.WriteLine("Adult saw doctor of type: {0}", doctor.GetType().Name);
}
}
public class Child : IPerson
{
public void VisitDoctor(IDoctor doctor)
{
Console.WriteLine("Child saw doctor of type: {0}", doctor.GetType().Name);
}
}
public class AdultDoctor : IDoctor
{
}
public class ChildDoctor : IDoctor
{
}
这些测试:
[Test]
public void AdultSeesDoctor()
{
var adult = new Adult();
adult.VisitDoctor(new AdultDoctor());
adult.VisitDoctor(new ChildDoctor()); // <-- Would like this to fail
}
[Test]
public void ChildSeesDoctor()
{
var child = new Child();
child.VisitDoctor(new AdultDoctor()); // <-- Would like this to fail
child.VisitDoctor(new ChildDoctor());
}
输出:
成人锯医生类型:AdultDoctor
成人锯医生类型:ChildDoctor
儿童锯医生类型:AdultDoctor
儿童锯医生类型:ChildDoctor
现在,我可以实现以下内容,如果成人尝试去看儿童医生,或者孩子尝试去看成人医生(抛出 a System.InvalidCastException
),则会引发运行时错误:
public interface IVisitDoctors<T> where T : IDoctor
{
void VisitDoctor(T doctor);
}
public class Child : IPerson
{
private readonly ChildDoctorVisitor _cdv = new ChildDoctorVisitor();
public void VisitDoctor(IDoctor doctor)
{
_cdv.VisitDoctor((ChildDoctor)doctor);
}
}
public class Adult : IPerson
{
private readonly AdultDoctorVisitor _adv = new AdultDoctorVisitor();
public void VisitDoctor(IDoctor doctor)
{
_adv.VisitDoctor((AdultDoctor)doctor);
}
}
您能否强制 的 类Adult
仅访问 类型 的医生,以便在访问类型AdultDoctor
的医生时引发编译时ChildDoctor
错误(反之亦然 的 类Child
)?