gpt4 book ai didi

c# - 在 .NET : good, 中隐藏继承的通用接口(interface)成员是坏的还是丑的?

转载 作者:太空狗 更新时间:2023-10-29 17:51:09 32 4
gpt4 key购买 nike

我知道在类实现中隐藏成员可能会导致调用“错误”成员的情况,具体取决于我如何转换我的实例,但是对于接口(interface)我不认为这可能是个问题而且我发现我自己经常编写这样的界面:

public interface INode
{
IEnumerable<INode> Children { get; }
}

public interface INode<N> : INode
where N : INode<N>
{
new IEnumerable<N> Children { get; }
}

public interface IAlpha : INode<IAlpha>
{ }

public interface IBeta : INode<IBeta>
{ }

我的代码中有一些地方只知道INode,所以 child 也应该是INode类型。

在其他地方我想知 Prop 体的类型——在我的示例 IAlphaIBeta 接口(interface)的实现中我希望 children 的类型与他们的相同 parent 。

所以我实现了一个 NodeBase 类,如下所示:

public abstract class NodeBase<N> : INode<N>
where N : INode<N>
{
protected readonly List<N> _children = new List<N>();

public IEnumerable<N> Children
{
get { return _children.AsEnumerable(); }
}

IEnumerable<INode> INode.Children
{
get { return this.Children.Cast<INode>(); }
}
}

实际实现中没有阴影,仅在接口(interface)中。

IAlphaIBeta 的具体实例如下所示:

public class Alpha : NodeBase<Alpha>, IAlpha
{
IEnumerable<IAlpha> INode<IAlpha>.Children
{
get { return this.Children.Cast<IAlpha>(); }
}
}

public class Beta : NodeBase<Beta>, IBeta
{
IEnumerable<IBeta> INode<IBeta>.Children
{
get { return this.Children.Cast<IBeta>(); }
}
}

同样,实现中没有阴影。

我现在可以像这样访问这些类型:

var alpha = new Alpha();
var beta = new Beta();

var alphaAsIAlpha = alpha as IAlpha;
var betaAsIBeta = beta as IBeta;

var alphaAsINode = alpha as INode;
var betaAsINode = beta as INode;

var alphaAsINodeAlpha = alpha as INode<Alpha>;
var betaAsINodeBeta = beta as INode<Beta>;

var alphaAsINodeIAlpha = alpha as INode<IAlpha>;
var betaAsINodeIBeta = beta as INode<IBeta>;

var alphaAsNodeBaseAlpha = alpha as NodeBase<Alpha>;
var betaAsNodeBaseBeta = beta as NodeBase<Beta>;

现在每个变量都有正确的强类型 Children 集合。

所以,我的问题很简单。使用这种模式的接口(interface)成员的阴影是好是坏还是丑陋?为什么?

最佳答案

我会说你遇到了一个相当复杂的场景,我通常尝试让事情变得比这更简单 - 但如果它适合你,我认为添加更多信息是可以的像这样。 (这似乎是合理的,直到你到达 IAlphaIBeta 位;没有这些接口(interface),AlphaBeta 根本不需要任何实现,调用者可以只使用 INode<IAlpha>INode<IBeta>相反。

特别注意 IEnumerable<T>有效地做同样的事情 - 诚然,不是将一个泛型与另一个隐藏在一起,而是将一个非泛型与一个泛型隐藏起来。

其他四点:

  • 您调用 AsEnumerableNodeBase毫无意义;来电者仍然可以转换为 List<T> .如果你想阻止这种情况,你可以做类似 Select(x => x) 的事情。 . (理论上 Skip(0) 可能 有效,但它可以 被优化掉;LINQ to Objects 没有很好地记录哪些运算符可以保证隐藏原始实现。Select 保证不会。实际上,Take(int.MaxValue) 也可以。)

  • 从 C# 4 开始,由于协变性,您的两个“叶”类可以得到简化:

    public class Alpha : NodeBase<Alpha>, IAlpha
    {
    IEnumerable<IAlpha> INode<IAlpha>.Children { get { return Children; } }
    }

    public class Beta : NodeBase<Beta>, IBeta
    {
    IEnumerable<IBeta> INode<IBeta>.Children { get { return Children; } }
    }
  • 从 C# 4 开始,您的 NodeBase实现INode.Children 如果您愿意限制 N 可以简化成为引用类型:

    public abstract class NodeBase<N> : INode<N>
    where N : class, INode<N> // Note the class constraint
    {
    ...

    IEnumerable<INode> INode.Children
    {
    get { return this.Children; }
    }
    }
  • 从 C# 4 开始,您可以声明 INode<N>N 中协变:

    public interface INode<out N> : INode

关于c# - 在 .NET : good, 中隐藏继承的通用接口(interface)成员是坏的还是丑的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7035781/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com