C#的协变返回利用泛型类型 [英] c# covariant return types utilizing generics

查看:112
本文介绍了C#的协变返回利用泛型类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是唯一的途径低于code实现协变返回类型?

Is the code below the only way to implement covariant return types?

public abstract class BaseApplication<T> {
    public T Employee{ get; set; }
}

public class Application : BaseApplication<ExistingEmployee> {}

public class NewApplication : BaseApplication<NewEmployee> {}

我希望能够建立一个应用程序或新的应用并将其从Employee属性返回相应的学历要求。

I want to be able to construct an Application or a NewApplication and have it return the appropriate Employee type from the Employee property.

var app = new Application();
var employee = app.Employee; // this should be of type ExistingEmployee

我相信这code工作正常,但它变得非常讨厌,当我有需要相同行为的若干属性。

I believe this code works fine, but it gets really nasty when I have several properties that require the same behavior.

是否有任何其他方式来实现这一行为?泛型或以其他方式?

Are there any other ways to implement this behavior? Generics or otherwise?

推荐答案

首先,在回答你的问题是否定的,C#不支持任何形式的返回类型的协方差虚拟覆盖。

First off, the answer to your question is no, C# does not support any form of return type covariance on virtual overrides.

若干回答者和评论者都表示没有在这个问题上没有协方差。这是不正确;原来的海报是完全正确的,因为他们没有来提出这个问题。

A number of answerers and commenters have said "there is no covariance in this question". This is incorrect; the original poster was entirely correct to pose the question as they did.

回想一下,协变映射是preserves一些存在和方向的映射其他关系。例如,从类型 T 来一个类型的映射的IEnumerable&LT; T&GT; 是协变的,因为它preserves分配相容关系。如果老虎是分配与动物兼容,那么下图的转化也preserved:的IEnumerable&LT; TIGER&GT; 是分配与的IEnumerable&LT兼容;动物方式&gt;

Recall that a covariant mapping is a mapping which preserves the existence and direction of some other relation. For example, the mapping from a type T to a type IEnumerable<T> is covariant because it preserves the assignment compatibility relation. If Tiger is assignment compatible with Animal, then the transformation under the map is also preserved: IEnumerable<Tiger> is assignment compatible with IEnumerable<Animal>.

这里的协映射是有点难以看到,但它仍然存在。这个问题本质上是这样的:这应该是合法的。

The covariant mapping here is a little bit harder to see, but it is still there. The question essentially is this: should this be legal?

class B
{
    public virtual Animal M() {...}
}
class D : B
{
    public override Tiger M() {...}
}

老虎是分配兼容动物。现在,让从类型T的映射的方法公共Tm值()。的这是否映射preserve兼容性的?也就是说,的如果老虎是动物用于分配的目的兼容,则是公共虎M()公共野兽M兼容( )虚拟压倒一切的目的是什么?

Tiger is assignment-compatible with Animal. Now make a mapping from a type T to a method "public T M()". Does that mapping preserve compatibility? That is, if Tiger is compatible with Animal for the purposes of assignment, then is public Tiger M() compatible with public Animal M() for the purposes of virtual overriding?

C#中的答案是否。 C#不支持这种协方差。

The answer in C# is "no". C# does not support this kind of covariance.

现在,我们已经建立了,这个问题一直使用正确类型代数术语,对实际问题的一些更多的心思问。最明显的一个问题是,物业甚至还没有被宣布为虚拟的,所以虚拟相容性的问题是没有实际意义。显而易见的第二个问题是一个获取;集;即使C#确实支持的返回类型,因为方差的与二传手的属性的类型不只是它的返回类型属性不能被协变,这也是其正式参数类型的。您需要逆变的正式参数类型,实现类型安全。如果我们允许与setter方法​​的属性返回类型的协方差,那么你就必须:

Now that we have established that the question has been asked using the correct type algebra jargon, a few more thoughts on the actual question. The obvious first problem is that the property has not even been declared as virtual, so questions of virtual compatibilty are moot. The obvious second problem is that a "get; set;" property could not be covariant even if C# did support return type covariance because the type of a property with a setter is not just its return type, it is also its formal parameter type. You need contravariance on formal parameter types to achieve type safety. If we allowed return type covariance on properties with setters then you'd have:

class B
{
    public virtual Animal Animal{ get; set;}
}
class D : B
{
    public override Tiger Animal { ... }
}

B b = new D();
b.Animal = new Giraffe();

哎,我们只是通过了一个长颈鹿给需要老虎似的。如果我们支持这项功能,我们就必须限制它返回类型(如我们做的通用接口分配兼容性协方差。)

and hey, we just passed a Giraffe to a setter that is expecting a Tiger. If we supported this feature we would have to restrict it to return types (as we do with assignment-compatibility covariance on generic interfaces.)

第三个问题是,该CLR不支持这种方差;如果我们要支持它在语言(我相信托管C ++做),那么我们将不得不做一些合理的英勇措施,以解决在CLR签名匹配的限制。

The third problem is that the CLR does not support this kind of variance; if we wanted to support it in the language (as I believe managed C++ does) then we would have to do some reasonably heroic measures to work around signature matching restrictions in the CLR.

您可以通过仔细定义新的方法有阴影的基类的类型适当的返回类型做自己的英雄措施:

You can do those heroic measures yourself by carefully defining "new" methods that have the appropriate return types that shadow their base class types:

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

现在,如果你有D的情况下,您会看到老虎类型属性。如果你将它转换为B,那么你看到的动物类型属性。在这两种情况下,你仍然可以通过受保护的成员获得的虚拟行为。

Now if you have an instance of D, you see the Tiger-typed property. If you cast it to B then you see the Animal-typed property. In either case, you still get the virtual behaviour via the protected member.

总之,我们没有计划要永远做这个功能,很抱歉。

In short, we have no plans to ever do this feature, sorry.

这篇关于C#的协变返回利用泛型类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆