Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在.NET中隐藏继承的通用接口成员:好、坏还是难看?_C#_.net_Oop_Generics_Shadowing - Fatal编程技术网

C# 在.NET中隐藏继承的通用接口成员:好、坏还是难看?

C# 在.NET中隐藏继承的通用接口成员:好、坏还是难看?,c#,.net,oop,generics,shadowing,C#,.net,Oop,Generics,Shadowing,我知道在类实现中隐藏成员可能会导致“错误”成员被调用的情况,具体取决于我如何转换实例,但对于接口,我不认为这是一个问题,我发现自己经常编写这样的接口: public interface INode { IEnumerable<INode> Children { get; } } public interface INode<N> : INode where N : INode<N> { new IEnumerable<N>

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

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>
{ }
在实际实现中没有阴影,只有在接口中

IAlpha
IBeta
的具体实例如下所示:

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>(); }
    }
}
公共类Alpha:NodeBase,IAlpha
{
可数INode.儿童
{
获取{返回this.Children.Cast();}
}
}
公共类测试版:NodeBase,IBeta
{
可数INode.儿童
{
获取{返回this.Children.Cast();}
}
}
同样,在实现中没有阴影

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

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>(); }
    }
}
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>;
var alpha=新alpha();
var beta=新的beta();
var alphasisalpha=α为IAlpha;
var betaAsIBeta=作为IBeta的beta;
var alphaAsINode=α作为索引节点;
var betaAsINode=βas INode;
var Alphasinodealpha=α为INode;
var betaAsINodeBeta=作为INode的β;
var alphaAsINodeIAlpha=α为INode;
var BetaAsinodeBeta=作为INode的beta;
var alphaasnodebaselpha=alpha作为NodeBase;
var betaAsNodeBaseBeta=作为节点基的beta;
现在,这些变量中的每一个都有正确的、强类型的
子类
集合


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

我想说的是,你有一个非常复杂的场景,我通常会尽量让事情简单一些——但如果它对你有效,我认为可以添加更多类似这样的信息。(在到达
IAlpha
IBeta
位之前,这似乎是合理的;没有这些接口,
Alpha
Beta
根本不需要任何实现,调用方只需使用
INode
INode

特别要注意的是,
IEnumerable
有效地做了同样的事情——不必承认,用一个泛型隐藏一个泛型,而是用一个泛型隐藏一个非泛型

其他四点:

  • NodeBase
    中调用
    AsEnumerable
    是毫无意义的;调用方仍然可以强制转换到
    List
    。如果要防止这种情况发生,可以执行类似
    Select(x=>x)
    (理论上是
    跳过(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开始,您可以在
    N
    中将
    INode
    声明为协变:

    public interface INode<out N> : INode
    
    公共接口INode:INode
    

为什么不简单地使用类型参数(即泛型类型的参数)来确定子节点的类型。这样INode仍然具有相同的语义,但根本不需要阴影
而且您确实在实现中有阴影,对INode的强制转换将导致与您在帖子中描述的问题相同的问题

为什么不简单地使用类型参数来确定子节点的类型。这样INode仍然具有相同的语义,但您不需要在all@Rune-你所说的“类型参数”是什么意思?@Enigmativity:我编辑了我的答案,以简化NodeBase对INode的实现。Children-我已经解决了我以前缺少的东西。@Jon-谢谢。非常感谢。感谢你的另一个优秀答案。关于
AsEnumerable
可转换回
列表的观点让我很困惑。在Rx中,
AsObservable
方法不支持ide源是可观察的。我只是假设
aseneumerable
也是如此。也许Rx的人就是很聪明。
public interface INode<out N> : INode