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

本文关键字:泛型 集合 返回 多态性 重载 运算符 | 更新日期: 2023-09-27 18:28:07

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

我有一个重载方法Connected,它检查段是否有一个公共端点。我想在抽象Segment类中定义2个Segment的重载,然后在各自的派生类中定义不同类型的重载,即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

所以本质上。。。

我试图替换以下代码(path1是Path,Segments是List,其中T是Segment)。

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

带有

Path<T> path1 = s1 + s2;

问题是使用的代码无法编译。

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

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

  1. 不要这样做。正如Jon所建议的,即使添加两个LineSegment,也可以始终返回一个Path<Segment>。我不喜欢这种"解决方案",因为这可能意味着你必须在所有地方使用强制转换。

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

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

    var path = Path<LineSegment>.Empty + lineSegment1 + lineSegment2;
    
  4. 使用奇怪的重复模板模式的变体:

    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的类继承)。我不喜欢这种解决方案。