Почему бы просто не использовать аргумент типа (который является аргументом универсального типа), чтобы определить тип потомка. Тогда INode все равно будет иметь ту же семантику, но вам вообще не понадобится дублирование. И у вас действительно есть дублирование при приведении реализации к INode, что приведет к тем же проблемам, которые вы описали в своем посте.

ю, что затенение членов в реализациях классов может привести к ситуациям, когда «неправильный» член может быть вызван в зависимости от того, как я разыграл свои экземпляры, но с интерфейсами я не вижу, что это может быть проблемой, и я нахожу себя пишущим интерфейсы. как это довольно часто:

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 поэтому дети также должны быть типаINode.

В других местах я хочу знать о конкретных типах - в реализации моего примераIAlpha & IBeta интерфейсы Я хочу, чтобы дети были набраны так же, как их родители.

Поэтому я реализую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>(); }
    }
}

Нет тени в реальной реализации, только в интерфейсах.

Конкретные случаи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>(); }
    }
}

Опять же, нет теней в реализациях.

Теперь я могу получить доступ к этим типам следующим образом:

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 коллекция.

Итак, мои вопросы просты. Является ли слежка за элементами интерфейса, использующими этот тип шаблона, хорошей, плохой или уродливой? И почему?

Ответы на вопрос(2)

Ваш ответ на вопрос