【问题标题】:Operator overloading polymorphism returning generic collection运算符重载多态性返回泛型集合
【发布时间】:2012-04-03 07:13:30
【问题描述】:

我想重载 + 运算符以将段添加在一起以形成路径。 我已经定义了一个路径,其中 T 是分段并包含一个列表(其中自然 T 是分段)。 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;
    }
}

@乔恩

所以本质上...

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

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

Path<T> path1 = s1 + s2;

问题是用的代码不能编译。

【问题讨论】:

  • 还有什么问题?顺便说一句:你没有检查你的输入值是否可以为空,执行时可能会失败。
  • 您仍然没有解释问题所在。您当前的代码是否有效?如果不是,它做什么(编译错误、异常……)?

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


【解决方案1】:

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

  1. 不要这样做。正如 Jon 所建议的那样,您始终可以返回一个 Path&lt;Segment&gt;,即使您添加了两个 LineSegments。我不喜欢这种“解决方案”,因为这可能意味着您必须在所有地方都使用强制转换。

  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>
    { }
    

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

【讨论】:

  • 谢谢,现在更好理解了。我没有太多所以2最好的选择。老实说,我本来可以在一开始就选择这种方式,但我内心的孩子想知道理想的方法。 var 和 dynamic 似乎出现了很多......我是否因为对这些一无所知而错过了?我只知道.NET 3.0
  • var 实际上并没有改变你的代码。它简化了您的代码,因此您不必拼出您的类型(我忽略了匿名类型,因为它们在这里不相关)。 dynamic 如果你有一些编译时类型的变量,但你想使用基于它们的运行时类型的运算符,这可能会很有用。例如对于Segment s1 = new LineSegment(), s2 = new LineSegment();,表达式s1 + s2 将执行Segment 的+ 运算符。如果要执行LineSegment的运算符,可以使用(dynamic)s1 + s2。但我不认为这在这里很有用。
猜你喜欢
  • 2017-04-28
  • 2014-06-15
  • 2015-01-29
  • 1970-01-01
  • 1970-01-01
  • 2023-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多