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

上一篇: 经过6次尝试后,无法将JSON请求发布到GCM

下一篇: 在重写虚拟方法时解决缺乏返回类型协方差的问题