c# - 在返回派生类型的派生接口(interface)中隐藏属性是否可以接受?

标签 c# interface covariance method-hiding

TL;DR

在接口(interface)中隐藏属性以便我可以更改其声明以返回原始属性的派生类型有什么问题?

我确信以前肯定有人问过这个问题,但我找不到它,对于这么长的问题深表歉意。

假设我有这种情况:

public interface A
{
    B TheB{get;}
}

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

public interface B{...}

public interface MoreSpecificB:B{...}

我希望 MoreSpecificA 的用户能够获得 B,即 MoreSpecificB。他们可以通过调用 TheB 并强制转换来完成此操作,或者可以调用方法 TheMoreSpecificB。我还可以像这样声明 MoreSpecificA :

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

这样他们现在就可以使用相同的方法并返回一个MoreSpecificB

使用new来隐藏方法让我感到紧张,那么为什么这是一个坏主意呢?在这里做这件事似乎是合理的。

在大多数情况下,我看到的一般建议似乎是使用泛型,但这似乎有一个问题,如果我有一个 MoreSpecificA 并且我想将其返回一个将返回类型声明为 A 的方法,那么我必须让 MoreSpecificA 扩展 A,这在访问 TheB 时会产生歧义> 在 MoreSpecificA 实例上,因为它不知道您想要 A.TheB 还是 MoreSpecificA.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;}
}

我的类(class)是

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添加了任何内容?

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

最佳答案

Or is my original plan of just hiding the method in the derived type to return a derived type of the original method ok?

只要它的意思完全相同,我认为就可以了。您可以在标准库中看到类似的内容,带有 IDbConnection.CreateCommand (返回 IDbCommand )和 SqlConnection.CreateCommand (返回 SqlCommand )例如。

在这种情况下,它使用 IDbConnection 的显式接口(interface)实现版本不同,但原理是一样的。

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

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

关于c# - 在返回派生类型的派生接口(interface)中隐藏属性是否可以接受?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9783083/

相关文章:

java - 带有接口(interface)的枚举 - 一般如何做?

c# - 使用 C# 在 asp.net 中将谷歌帐户添加到我的网站

java - 实现接口(interface)的单例类

c# - 使用 Azure.Data.Tables SDK 在 Azure 表存储中插入批处理似乎不可行

java - 连接两个 Java 应用程序的适当方法

c# - C# 数组中的协方差被破坏?

java - 类的集合和继承

c# - 使用更指定的返回类型(协方差)覆盖抽象属性

c# - 有没有办法检索事件的委托(delegate)

c# - 如何在 c# WPF 框架中禁用导航快捷方式