在树中的泛型

时间:2016-05-30 13:01:27

标签: c# generics tree

我有一个段类,它是树中的一个节点。没有Tree课程。树只是由细分组成。

public abstract class Segment 
{
    public List<Segment> Descendants { get; } => new List<Segment> Descendants;
    public abstract SegmentVisual VisualRepresentation { get; }
}

SegmentVisual是用于将片段绘制到屏幕的类。这两个类都是抽象的,因为我有不同类型的段,每个都需要以不同的方式绘制。

以下是SegmentVisual的样子:

public abstract class SegmentVisual : DrawingVisual 
{
    protected SegmentVisual(Segment owner){
        this.Owner = owner;
    }

    public Segment Owner { get; }
    public List<SegmentVisual> Descendants { get; } = new List<SegmentVisual>();

    public void Redraw()
    {
        this.RedrawItself();

        foreach (SegmentVisual visual in this.Visuals)
        {
            visual.Redraw();
        }
    }

    public abstract void RedrawItself();
}

就像Segment一样,Visual也有后代,所以可以在屏幕上添加一个视觉来绘制自己及其所有后代

这是一个实现:

public class LineSegment : Segment
{
    public LineSegment()
    {
        this.VisualRepresentation = new LineSegmentVisual(this);
    }

    public override SegmentVisual VisualRepresentation { get; }

    public Pen Stroke { get; set; }
}

public class LineSegmentVisual : SegmentVisual
{
    public LineSegmentVisual(LineSegment owner) // Resharper suggests this can be Segment base class
        : base(owner)
    {
    }

    public override void RedrawItself()
    {
        using (DrawingContext ctx = this.RenderOpen())
        {
            var owner = (LineSegment)this.Owner;
            ctx.DrawLine(owner.Stroke, this.Owner.Position, this.Owner.ControlPointPos);
        }
    }
}

我的问题是最后一堂课。你可以看到ReSharper的建议。我一直都不喜欢摔倒。如果我不得不在其他地方找回主人,我将不得不垂头丧气再次获得Stroke财产。

如果我SegmentVisual通用SegmentVisual<T>,其所有者为T,则会引入新的障碍,因为现在SegmentVisual只能包含{{1}的后代不应该是这种情况,因为我希望它包含任何类型的SegmentVisual<T>,我只希望所有者被强类型化。

我只希望SegmentVisual能够对应于特定的类,以便强类型化SegmentVisual属性。我似乎无法解决这个问题。

2 个答案:

答案 0 :(得分:1)

您可以使用new在子类中声明强类型Owner

public class LineSegmentVisual : SegmentVisual
{
    new LineSegment Owner { get { return (LineSegment)base.Owner; } }

    public LineSegmentVisual(Segment owner)
        : base(owner)
    {
    }

    public override void RedrawItself()
    {
        using (DrawingContext ctx = this.RenderOpen())
        {
            var owner = this.Owner;
            ctx.DrawLine(owner.Stroke, this.Owner.Position, this.Owner.ControlPointPos);
        }
    }
}

每次调用base.Owner时都会以this.Owner的方式投放,但至少你会避免重复代码。

第二种方式是使用继承。使用基本功能

声明SegmentVisual
abstract class SegmentVisual
{
    public List<SegmentVisual> Descendants { get; private set; }

    ...
}
带有强类型所有者的

OwnedSegmentVisual

abstract class OwnedSegmentVisual<TOwner>: SegmentVisual where TOwner: Segment
{
    public TOwner Owner { get; private set; }

    protected OwnedSegmentVisual(TOwner owner)
    {
        Owner = owner;
    }
}

Owner可以在没有强制转换的子类中使用,而常用功能只能使用SegmentVisual

第三种方式是使用泛型协方差,但您必须为您的类型声明接口:

public class Program
{
    public static void Main()
    {
        var sv = new LineSegmentVisual();
        sv.Descendants = new List<ISegmentVisual<Segment>> { new SquareSegmentVisual() };
    }
}


abstract class Segment {}

class LineSegment : Segment {}

class SquareSegment: Segment {}

interface ISegmentVisual<out TOwner>
{
    TOwner Owner { get; }

    List<ISegmentVisual<Segment>> Descendants { get; }
}

class LineSegmentVisual : ISegmentVisual<LineSegment>
{
    public LineSegment Owner { get; set; }
    public List<ISegmentVisual<Segment>> Descendants { get; set; }
}

class SquareSegmentVisual : ISegmentVisual<SquareSegment>
{
    public SquareSegment Owner { get; set; }
    public List<ISegmentVisual<Segment>> Descendants { get; set; }
}

希望,这会有所帮助。

答案 1 :(得分:1)

C#不支持返回类型差异。也就是说,以下是不可能的:

class Foo
{
    virtual Base Owner{ get; }
}

class Bar: Foo
{
    override Derived Owner { get; } // where Dervided: Base
}

您将收到编译时错误,通知您Derived未覆盖任何合适的方法。我发现在C#中缺少这个功能实在是有点烦人,虽然它已经上线了几次,未来的版本它从来没有削减过。说实话,相互竞争的功能已经变得更加有趣和有用了。

IMO你有两个合理的选择。一个是隐藏Owner

class Bar: Foo
{
    new Derived Owner { get { return base.Owner as Derived; } // where Derived: Base
}

另一个是使用明确实现的接口:

interface IOwnable
{
    Base Owner { get; }
}

class Foo: IOwnable
{
    Base IOwnable.Owner { get; }
}

class Bar: Foo
{
    Derived Owner { get { return ((IOwnable)base).Owner as Derived; } // where Derived: Base
}