Workaround for lack of return type covariance when overriding virtual methods
is there any way to 'hack' or 'coerce' covariant overrides in to C#?
For example:
public class Alpha {
public virtual Alpha DoSomething() {
return AlphaFactory.GetAlphaFromSomewhere();
}
}
public class Beta : Alpha {
public override Beta DoSomething() {
return BetaFactory.GetBetaFromSomewhere();
}
}
Unfortunately, C# doesn't support this (which seems a bit ridiculous, but that's neither here nor there).
I thought I might have an answer with method hiding:
new public Beta DoSomething() {
return BetaFactory.GetBetaFromSomewhere();
}
But this doesn't add the entry in to the 'vtable', it just basically declares a brand new method with the same name, and as such means that accessing Beta
s through a pointer to an Alpha
will call Alpha.DoSomething()
.
So, any good tricks?
你可以用泛型做一些漂亮的小东西。
public class Alpha<T> where T: Alpha<T> {
public virtual T DoSomething() {
throw new NotImplementedException();
}
}
public class Beta : Alpha<Beta> {
public override Beta DoSomething() {
throw new NotImplementedException();
}
}
You can always wrap the method inside another method
public class Alpha {
public virtual Alpha DoSomething() {
return AlphaFactory.GetAlphaFromSomewhere();
}
}
public class Beta : Alpha {
private Beta Helper() {
return BetaFactory.GetBetaFromSomewhere();
}
public Beta DoSomething() {
return Helper();
}
public override Alpha DoSomething() {
return Helper();
}
}
If there are lots of methods though, you might want to autogenerate these wrappers. If that's too demanding, the solution of @recursive is all there is left.
Because there is no great benefit in return type covariance in most cases.
If you are calling virtual Alpha.DoSomething
then you really don't know if you are getting back an Alpha
or a Beta
so how does return type covariance help? You will have to store the result in an Alpha
typed object anyhow because it's the only type that can admit Alpha
s or Beta
s.
On the other hand, if you statically know that you are calling Beta.DoSomething
then you can either: directly use the returned Alpha
typed object because you will be accessing common functionality or virtual methods so you don't care if it's really a Beta
(the virtual call will resolve to the right type) or you can directly choose to (runtime safe) cast to Beta
in order to access specific implementation.
Edit: removed the type safe issue. I barely thought it through and evidently return type covariance would be safe. The rest of the answer stands though. I can't find anything particularly interesting in this feature, at least in the way the OP wants to use it: avoid a safe cheap cast?
链接地址: http://www.djcxy.com/p/81484.html