重写虚拟方法时缺少返回类型协方差的解决方法

时间:2014-09-12 22:27:33

标签: c# methods covariance vtable

有什么办法可以解决这个问题吗?或者'强迫'协变覆盖到C#?

例如:

public class Alpha {
    public virtual Alpha DoSomething() {
        return AlphaFactory.GetAlphaFromSomewhere();
    }
}
public class Beta : Alpha {
    public override Beta DoSomething() {
        return BetaFactory.GetBetaFromSomewhere();
    }
}

不幸的是,C#并不支持这一点(这看起来有点荒谬,但那里既不存在也不存在)。

我以为我可能会有方法隐藏的答案:

new public Beta DoSomething() {
    return BetaFactory.GetBetaFromSomewhere();
}

但是这并没有将条目添加到' vtable',它只是基本上声明了一个具有相同名称的全新方法,因此意味着访问Beta s通过指向Alpha的指针将调用Alpha.DoSomething()

那么,有什么好的伎俩吗?

3 个答案:

答案 0 :(得分:5)

你可以用泛型做一些非常好的东西。

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

答案 1 :(得分:1)

您始终可以将方法包装在另一个方法中

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

如果有很多方法,您可能想要自动生成这些包装器。如果这个要求太高,那么@recursive的解决方案就是剩下的。

答案 2 :(得分:0)

因为在大多数情况下,返回类型协方差没有很大的好处。

如果您呼叫虚拟Alpha.DoSomething,那么您真的不知道您是否正在取回AlphaBeta那么返回类型协方差如何帮助?您无论如何都必须将结果存储在Alpha类型的对象中,因为它是唯一可以接纳AlphaBeta的类型。

另一方面,如果您静态地知道您正在调用Beta.DoSomething,那么您可以:直接使用返回的Alpha类型对象,因为您将访问公共功能或虚拟方法让你不在乎它是否真的是Beta(虚拟调用将解析为正确的类型),或者你可以直接选择(运行时安全)强制转换为{{ 1}}以便访问特定的实现。

编辑:删除了类型安全问题。我几乎没有想过它,显然返回类型协方差是安全的。答案的其余部分虽然如此。我无法在这个功能中找到任何特别有趣的东西,至少在OP想要使用它的方式:避免安全的廉价演员?