在派生接口中隐藏属性并返回派生类型是否可以接受?

时间:2012-03-20 07:51:08

标签: c# interface covariance method-hiding

TL; DR

在界面中隐藏属性有什么问题,以便我可以更改其声明以返回原始属性的派生类型?

我确信之前一定会被问过,但我找不到它,并为长期问题道歉。

说我有这种情况:

public interface A
{
    B TheB{get;}
}

public interface MoreSpecificA : A
{
    MoreSpecificB TheMoreSpecificB{get;}
}

public interface B{...}

public interface MoreSpecificB:B{...}

我希望MoreSpecificA的用户能够获得MoreSpecificB的B。他们可以通过调用TheB并投射它来执行此操作,也可以调用方法TheMoreSpecificB。我也可以这样声明MoreSpecificA

public interface MoreSpecificA : A
{
    new MoreSpecificB TheB{get;}
}

现在他们可以使用相同的方法并取回MoreSpecificB

使用new来隐藏一种方法让我的牙齿处于边缘,那么为什么这是一个坏主意呢?这里做起来似乎是合理的。

我在大多数情况下看到的一般建议似乎是使用泛型,但这似乎有一个问题,如果我有MoreSpecificA并且我想以一种方法返回它将返回类型声明为A然后我必须MoreSpecificA扩展A,这会在TheB实例上访问MoreSpecificA时产生歧义,因为它不知道如果您需要A.TheBMoreSpecificA.TheB

public interface ABase<T> where T : B
{
    T TheB{get;}
}

public interface A : ABase<B>
{        
}

public interface MoreSpecificA : ABase<MoreSpecificB>,A
{        
}

public class blah
{
    public A GetA(MoreSpecificA specificA)
    {
        return specificA; //can't do this unless MoreSpecificA extends A 
    }

    public B GetB(MoreSpecificA specificA)
    {
        return specificA.TheB; //compiler complains about ambiguity here, if MoreSpcificA extends A
    }
}

可以通过在MoreSpecificA上声明一个新的TheB来解决(但新问题再次出现)。

如果MoreSpecificA没有扩展A,那么上面的类blah中的第一个方法就会抱怨,因为MoreSpcificA无法转换为A.

在写这篇文章的同时,我注意到如果我声明我的BaseA是这样的逆变:

public interface ABase<out T> where T : B
{
    T TheB{get;}
}

和我的班级

public class blah
{
    public ABase<B> GetA(MoreSpecificA specificA)
    {
        return specificA; 
    }

    public B GetB(MoreSpecificA specificA)
    {
        return specificA.TheB; //compiler complains about ambiguity here
    }
}

然后我充分利用这两个世界。此解决方案的适用性是否取决于A是否向ABase添加了任何内容?

或者我的原始计划是将方法隐藏在派生类型中以返回原始方法的派生类型吗?

1 个答案:

答案 0 :(得分:2)

  

或者我的原始计划是将方法隐藏在派生类型中以返回原始方法的派生类型吗?

只要它意味着完全相同的东西,我认为这没关系。您可以在标准库中看到类似的内容,例如IDbConnection.CreateCommand(返回IDbCommand)和SqlConnection.CreateCommand(返回SqlCommand)。

在这种情况下,它使用IDbConnection版本的显式接口实现,但它的原理相同。

您还可以在IEnumerator<T>.Current vs IEnumerator.CurrentIEnumerable<T>.GetEnumerator() vs IEnumerable.GetEnumerator()中看到它。

我只会在更弱类型的方法 的实现返回调用更强类型方法的结果但使用隐式转换的情况下使用它。当他们真正开始做不同的事情时,后来变得更难以推理。