运算符重载与C#扩展方法

我正在尝试使用扩展方法将操作符重载添加到C# StringBuilder类。 具体来说,给定的StringBuilder sb ,我想sb += "text"等于sb.Append("text")

以下是为StringBuilder创build扩展方法的语法:

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

它成功地将这个扩展方法添加到了StringBuilder

不幸的是,运算符重载似乎不起作用:

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

在其他问题中,关键字在这种情况下是不允许的。

是否可以通过扩展方法添加运算符重载? 如果是这样,那么有什么正确的方法呢?

这是目前不可能的,因为扩展方法必须在静态类中,静态类不能有运算符重载。

C#语言PM的Mads Torgersen说:

…对于Orcas版本,我们决定采取谨慎的方法,只添加常规扩展方法,而不是扩展属性,事件,运算符,静态方法等等。定期扩展方法是我们需要的LINQ,他们有一个语法上最小的devise,不能容易地模仿一些其他成员types。

我们越来越意识到其他types的扩展成员可能是有用的,所以我们将在Orcas之后回到这个问题。 不过没有保证!

编辑:

我刚刚注意到,Mads在同一篇文章中写道:

我很抱歉地报告说,我们不会在下一个版本中这样做。 在我们的计划中,我们确实非常认真地对待推广成员,并花费了很大的努力试图让他们正确,但最终我们无法得到足够的顺利,并决定让位于其他有趣的function。

这仍然是我们的未来版本。 如果我们得到大量有吸引力的场景,可以帮助推动正确的devise,将会有所帮助。


目前这个function在C#8.0的桌面上(可能)。 Mads 在这里谈到更多关于实施的事情。

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

 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类从StringBuilderWrapper声明一个隐式转换运算符 , 声明所需的+运算符。 这样,一个StringBuilder可以被传递给ReceiveImportantMessage ,它将被悄悄地转换成一个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()); 

我创build了一篇关于使用类似方法来使IComparable更易于理解的文章。

看起来目前这是不可能的 – 在Microsoft Connect上有一个公开的反馈问题要求这个特性:

http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=168224

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

尽pipe不可能执行操作符,但您始终可以创buildAdd(或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 + =(东西)。

在阅读这里的答案(并看到答案是“否”),为了我的特殊需要,我使用了一个扩展方法,结合了sb.AppendLine和sb.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); 

不是一个普遍的答案,但可能是未来寻求这种东西的人的兴趣。

它可能绑定一个包装和扩展,但不可能做到这一点。 你以完全击败目标的垃圾结束。 我在这里有一个post,但它没有任何价值。

顺便说一句,所有的数字转换在string生成器中创build垃圾需要修复。 我不得不写一个包装,它的工作,我用它。 这是值得一读的。