我有一个段类,它是树中的一个节点。没有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
属性。我似乎无法解决这个问题。
答案 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
}