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

有没有办法'破解'或'强制'协变覆盖到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'中,它只是基本上声明了一个全新的名称相同的方法,这意味着通过指向Alpha的指针访问Beta会调用Alpha.DoSomething()

那么,有什么好的技巧?


你可以用泛型做一些漂亮的小东西。

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

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

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的解决方案就剩下了。


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

如果你正在调用虚拟Alpha.DoSomething那么你真的不知道你是否得到一个Alpha或一个Beta那么返回类型协方差如何帮助? 无论如何,您必须将结果存储在Alpha类型对象中,因为它是唯一可以接受AlphaBeta的类型。

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

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

链接地址: http://www.djcxy.com/p/81483.html

上一篇: Workaround for lack of return type covariance when overriding virtual methods

下一篇: Undefined local variable based on syntax in Ruby