Bri*_*ian 26 c# generics covariance
下面的代码是实现协变返回类型的唯一方法吗?
public abstract class BaseApplication<T> {
public T Employee{ get; set; }
}
public class Application : BaseApplication<ExistingEmployee> {}
public class NewApplication : BaseApplication<NewEmployee> {}
Run Code Online (Sandbox Code Playgroud)
我希望能够构造一个Application或NewApplication并让它从Employee属性返回适当的Employee类型.
var app = new Application();
var employee = app.Employee; // this should be of type ExistingEmployee
Run Code Online (Sandbox Code Playgroud)
我相信这段代码工作得很好,但是当我有几个需要相同行为的属性时,它变得非常讨厌.
有没有其他方法来实现这种行为?泛型或其他?
Eri*_*ert 68
首先,你的问题的答案是否定的,C#不支持虚拟覆盖的任何形式的返回类型协方差.
一些回答者和评论者说"这个问题没有协方差".这是不正确的; 原始海报完全正确,就像他们一样提出问题.
回想一下,协变映射是一种保留其他关系的存在和方向的映射.例如,从类型T到类型的映射IEnumerable<T>是协变的,因为它保留了赋值兼容性关系.如果Tiger与Animal兼容,那么地图下的转换也会保留:IEnumerable<Tiger>与赋值兼容IEnumerable<Animal>.
这里的协变映射有点难以看到,但它仍然存在.问题基本上是这样的:这应该是合法的吗?
class B
{
public virtual Animal M() {...}
}
class D : B
{
public override Tiger M() {...}
}
Run Code Online (Sandbox Code Playgroud)
Tiger与Animal分配兼容.现在进行从类型T到方法"public TM()"的映射. 该映射是否保持兼容性?也就是说,如果Tiger为了分配目的与Animal兼容,那么为了虚拟覆盖的目的是否public Tiger M()兼容public Animal M()?
C#的答案是"不".C#不支持这种协方差.
现在我们已经确定问题是使用正确的类型代数术语提出来的,还有一些关于实际问题的想法.显而易见的第一个问题是该属性甚至没有被声明为虚拟属性,因此虚拟兼容性的问题没有实际意义.显而易见的第二个问题是"得到;设定;" 即使C#支持返回类型协方差,属性也不能协变,因为带有setter的属性的类型不仅仅是它的返回类型,它也是它的形式参数类型.您需要在形式参数类型上进行逆转才能实现类型安全.如果我们允许带有setter的属性的返回类型协方差,那么你将拥有:
class B
{
public virtual Animal Animal{ get; set;}
}
class D : B
{
public override Tiger Animal { ... }
}
B b = new D();
b.Animal = new Giraffe();
Run Code Online (Sandbox Code Playgroud)
嘿,我们只是把一头长颈鹿带到了一个期待老虎的二传手.如果我们支持此功能,我们必须将其限制为返回类型(就像我们在通用接口上的赋值兼容性协方差一样).
第三个问题是CLR不支持这种方差; 如果我们想用语言支持它(因为我相信托管的C++确实如此),那么我们将不得不做一些合理的英雄措施来解决CLR中的签名匹配限制.
您可以通过仔细定义具有影响其基类类型的适当返回类型的"新"方法来自行执行这些英雄测量:
abstract class B
{
protected abstract Animal ProtectedM();
public Animal Animal { get { return this.ProtectedM(); } }
}
class D : B
{
protected override Animal ProtectedM() { return new Tiger(); }
public new Tiger Animal { get { return (Tiger)this.ProtectedM(); } }
}
Run Code Online (Sandbox Code Playgroud)
现在,如果你有一个D实例,你会看到Tiger类型的属性.如果将其强制转换为B,则会看到Animal-typed属性.在任何一种情况下,您仍然可以通过受保护的成员获得虚拟行为.
简而言之,对不起,我们没有计划做过这个功能.
| 归档时间: |
|
| 查看次数: |
6140 次 |
| 最近记录: |