运算符重载多态返回泛型集合

时间:2012-03-18 15:04:50

标签: c# generics polymorphism operator-overloading abstract-class

我想重载+运算符以将段添加到一起以形成Path。 我已经定义了一个Path,其中T是Segment并包含一个List(其中T自然是Segment)。 Segment是各种类型Segment的抽象基类,即LineSegment

我有一个重载方法Connected,它检查段是否有一个公共端点。我想在抽象的Segment类中为2个Segments定义重载,然后在不同的派生类中为不同的类型定义Segment和LineSegment。

public static Path<T> operator +(Segment s1, Segment s2)
{
    if (s1.Connected(s2))
    {
        List<Segment> slist = new List<Segment>();
        slist.Add(s1);
        slist.Add(s2);
        Path<T> p = new Path<T>(slist);
        return p;
    }
    else
    {
        return null;
    }
}

@Jon

基本上......

我试图替换以下代码(路径1是路径,分段是列表,其中T是段)。

Path<T> path1 = new Path<T>(s1);
path1.Segments.Add(s2);

Path<T> path1 = s1 + s2;

问题是代码无法编译。

1 个答案:

答案 0 :(得分:1)

由于C#不支持泛型运算符,我认为没有简单的方法可以做到这一点。但我可以想象几种方法让它发挥作用:

  1. 不要这样做。正如Jon建议的那样,即使你添加了两个Path<Segment>,你总是可以返回LineSegment。我不喜欢这个“解决方案”,因为它可能意味着你必须在整个地方使用演员阵容。

  2. 将运算符添加到从Segment继承的每个类型。这意味着重复代码,但我认为这是最好的选择。例如,LineSegment的运算符将如下所示:

    public static Path<LineSegment> operator +(LineSegment s1, LineSegment s2)
    
  3. 不要将两个段一起添加,而是将它们添加到空路径中。如果你这样做,那么最好是Path不可变:

    var path = Path<LineSegment>.Empty + lineSegment1 + lineSegment2;
    
  4. 使用curiously recurring template pattern的变体:

    class SegmentBase<T> where T : SegmentBase<T>
    {
        public static Path<T> operator +(SegmentBase<T> s1, SegmentBase<T> s2)
        {
            return new Path<T>(new List<T> { (T)s1, (T)s2 });
        }
    }
    
    class LineSegment : SegmentBase<LineSegment>
    { }
    

    如果你这样做,你没有任何重复,但感觉就像一个黑客,它可能会使你的继承层次结构复杂化(你不能从指定T的类继承)。我不喜欢这个解决方案。