使用 C # 扩展方法进行运算符重载

我正在尝试使用扩展方法向 C # StringBuilder类添加一个操作符重载。具体地说,给定 StringBuilder sb,我希望 sb += "text"等效于 sb.Append("text")

下面是为 StringBuilder创建扩展方法的语法:

public static class sbExtensions
{
public static StringBuilder blah(this StringBuilder sb)
{
return sb;
}
}

它成功地将 blah扩展方法添加到 StringBuilder

不幸的是,运算符重载似乎并不奏效:

public static class sbExtensions
{
public static StringBuilder operator +(this StringBuilder sb, string s)
{
return sb.Append(s);
}
}

在其他问题中,关键字 this在这个上下文中是不允许的。

通过扩展方法增加操作符重载是可能的吗? 如果可能,正确的方法是什么?

57242 次浏览

这在当前是不可能的,因为扩展方法必须在静态类中,而且静态类不能有运算符重载。但是 对于 C # 的未来版本,正在讨论 < em > some 特性。Mads 谈了更多关于实现 在这段2017年的视频里的内容。

关于为什么目前还没有实现,C # Language PM 的 Mads Torgersen 说:

我们决定释放虎鲸 采取谨慎的做法 只使用常规扩展方法,如 反对扩展属性, 事件、运算符、静态方法等 定期扩展方法包括 我们需要 LINQ 的东西,他们已经有了 语法上的最小化设计 不容易被某些人模仿 其他类型的成员。

我们越来越意识到 其他类型的扩展成员 可能是有用的,所以我们会回来 在逆戟鲸之后,没有 但我保证!

同一篇文章下面进一步说明:

很抱歉,我们不会 在下一个版本做这个。我们 确实非常喜欢扩展会员 认真地在我们的计划,并花了一个 我费了很大劲才抓到他们 没错,但最后我们没能 它足够顺利,并决定给予 其他有趣的特征。

我们以后还会关注这件事 释放。如果我们得到了什么将有所帮助 很多引人注目的场景 可以帮助驱动正确的设计。

目前看来这是不可能的-有一个开放的反馈问题,要求这个非常特别的功能在微软连接:

返回 http://connect.microsoft.com/visualstudio/feedback/viewfeedback.aspx 页面反馈 ID = 168224

表明它可能会出现在未来的版本中,但不会在当前版本中实现。

如果你控制你想要使用这个“扩展操作符”的地方(你通常使用扩展方法) ,你可以这样做:

class Program {


static void Main(string[] args) {
StringBuilder sb = new StringBuilder();
ReceiveImportantMessage(sb);
Console.WriteLine(sb.ToString());
}


// the important thing is to use StringBuilderWrapper!
private static void ReceiveImportantMessage(StringBuilderWrapper sb) {
sb += "Hello World!";
}


}


public class StringBuilderWrapper {


public StringBuilderWrapper(StringBuilder sb) { StringBuilder = sb; }
public StringBuilder StringBuilder { get; private set; }


public static implicit operator StringBuilderWrapper(StringBuilder sb) {
return new StringBuilderWrapper(sb);
}


public static StringBuilderWrapper operator +(StringBuilderWrapper sbw, string s) {
sbw.StringBuilder.Append(s);
return sbw;
}


}

StringBuilderWrapper类从 StringBuilder 还有声明所需的 +操作符声明一个 隐式转换运算符。通过这种方式,可以将 StringBuilder传递给 ReceiveImportantMessageReceiveImportantMessage将静默地转换为 StringBuilderWrapper,在这里可以使用 +操作符。

为了使这个事实对调用者更加透明,您可以声明 ReceiveImportantMessage为接受 StringBuilder,并使用如下代码:

  private static void ReceiveImportantMessage(StringBuilder sb) {
StringBuilderWrapper sbw = sb;
sbw += "Hello World!";
}

或者,要在已经使用 StringBuilder的地方内联使用它,您可以简单地这样做:

 StringBuilder sb = new StringBuilder();
StringBuilderWrapper sbw = sb;
sbw += "Hello World!";
Console.WriteLine(sb.ToString());

我创建了关于使用类似的方法使 IComparable更容易理解的 一根柱子

尽管不可能使用这些操作符,但您总是可以创建 Add (或 Concat)、 Subtract 和 Compare 方法... ..。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace Whatever.Test
{
public static class Extensions
{
public static int Compare(this MyObject t1, MyObject t2)
{
if(t1.SomeValueField < t2.SomeValueField )
return -1;
else if (t1.SomeValueField > t2.SomeValueField )
{
return 1;
}
else
{
return 0;
}
}


public static MyObject Add(this MyObject t1, MyObject t2)
{
var newObject = new MyObject();
//do something
return newObject;


}


public static MyObject Subtract(this MyObject t1, MyObject t2)
{
var newObject= new MyObject();
//do something
return newObject;
}
}




}

哈! 我也是怀着同样的愿望在查“运算符重载”对于 sb += (thing)

在阅读了这里的答案(看到答案是“否”)之后,为了满足我的特殊需要,我使用了一种结合了 sb.AppendLinesb.AppendFormat的扩展方法,它看起来比这两种方法都要整洁。

public static class SomeExtensions
{
public static void Line(this StringBuilder sb, string format, params object[] args)
{
string s = String.Format(format + "\n", args);
sb.Append(s);
}
}

所以,

sb.Line("the first thing is {0}", first);
sb.Line("the second thing is {0}", second);

这不是一个普遍的答案,但可能会引起未来的探索者对这类事情的兴趣。

有可能用一个包装和扩展来装配它,但是不可能正确地做到这一点。你用垃圾结束,这完全违背了目的。 我在这上面贴了个帖子,但是没用。

所有数值转换都会在字符串生成器中创建需要修复的垃圾。我不得不写一个包装,这是工作,我使用它。这是值得研究的。