重载'+'的不可变列表是否有意义?

时间:2010-08-07 00:32:49

标签: c# operator-overloading immutability

它当然不会脱离.NET框架的标准做法。当我看到a + b时,我总是假设会创建一些新内容。

static void Main(string[] args)
{
    var list = BuildList(ImmutableList<int>.Empty);
    var sum = (list + 500).Sum();
    Console.WriteLine(sum);
    Console.ReadLine();
}

static ImmutableList<int> BuildList(ImmutableList<int> list)
{
    if (list.Count < 1000)
    {
        return BuildList(list + list.Count);
    }
    return list;
}

更新

请参阅Jon Skeet关于name methods on immutable lists的内容的帖子。

令人惊讶的回应

我很惊讶地看到这么多答案都认为这是有道理的。原则上我也同意,但是对于我来说,阅读冗长的代码比阅读简洁,代码简洁的人更容易。从我的工作经验来看,他们似乎占多数。

5 个答案:

答案 0 :(得分:6)

我个人不建议像+这样的运算符重载任何不打算被视为基元的类。特别是,在我看来,收藏品永远不应超载运营商。

当你有一个小的不可变类或结构,其行为类似于“原始”类型时,运算符重载是有意义的。但是,当您开始尝试为其他类执行此操作时,它确实会影响可维护性。

我建议改为显式方法调用。


阅读评论后,我的建议是使用Concat()(以匹配框架中的Enumerable.Concat)。我更喜欢的另一种选择是Construct(),ala cons(尽管通常是前言),以便明确使用:

var list = BuildList(ImmutableList<int>.Empty);
var list2 = list.Concat(500); 
// Or: var list2 = list.Construct(500);

答案 1 :(得分:5)

重载+的不可变字符列表是有意义的;我们称它们为弦乐。相比之下,您可以说,重载+运算符以调用Concat操作的任何事物的不可变列表都是有意义的。

顺便说一下,我最近创建了一个与你所描述的类似的功能:

public static IEnumerable<T> Append<T>(this IEnumerable<T> list, T item)
{
    foreach (T i in list)
        yield return i;
    yield return item;
}

我决定Append在列表中添加一个元素,而Concat将整个列表添加到列表的末尾。

答案 2 :(得分:2)

+在这种情况下的含义是什么?我似乎真的不清楚(没有阅读代码)。 IList + IList我可以看到可能是联盟运营商或组合列表(保留重复)或任何其他数量的东西。 IList + int只是让我困惑。在我看来,一个名称清晰的方法将使得代码比人们必须查找的运算符更易读,或者每次使用重载运算符时都会发表注释。

答案 3 :(得分:2)

关于运营商的一点是,人们期望它们相对有效。没有什么可说的,这应该成立,但人们确实期待它。

如果在内部,这样一个列表的结构允许你创建一个连接列表,让它存储对它所源自的两个的引用(很可能,特别是考虑到不变性否定了混淆副作用的风险),然后我会去的。如果它可能需要做一个相对昂贵的操作,那么我不会。 “concatenate()”可能会让某人考虑“我真的需要在这个紧密的循环中移动这么多的内存,我现在正在这里,或者我应该考虑采用不同的方法”,当时这种想法是合适的。< / p>

答案 4 :(得分:1)

我会这样做。

毕竟,字符串是一个字符列表。

是的,如果我看到&lt; list&gt; +&lt; list&gt;我会立即想到连接(唯一的另一种可能性是矢量和,这很少见)。