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

Jud*_*red 167 c# extension-methods operator-overloading

我正在尝试使用扩展方法向C#StringBuilder类添加一个operater重载.具体来说,给定StringBuilder sb,我想sb += "text"成为等同于sb.Append("text").

以下是为以下内容创建扩展方法的语法StringBuilder:

public static class sbExtensions
{
    public static StringBuilder blah(this StringBuilder sb)
    {
        return sb;
    }
} 
Run Code Online (Sandbox Code Playgroud)

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

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

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

除其他问题外,this在此上下文中不允许使用关键字.

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

Jac*_*all 147

目前这是不可能的,因为扩展方法必须是静态类,静态类不能有操作符重载.

Mads Torgersen,C#语言PM说:

...对于Orcas版本,我们决定采取谨慎的方法,只添加常规扩展方法,而不是扩展属性,事件,运算符,静态方法等.常规扩展方法是我们LINQ所需要的,他们有一种语法上最小的设计,对于某些其他成员类型来说,这些设计无法轻易模仿.

我们越来越意识到其他类型的扩展成员可能会有用,因此我们将在Orcas之后回到这个问题.不过没有保证!

编辑:

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

很抱歉,我们不会在下一个版本中这样做.我们确实在我们的计划中非常认真地对待扩展成员,并且花费了大量精力来努力使它们正确,但最终我们无法让它变得平滑,并决定让位于其他有趣的功能.

对于未来的版本,这仍然是我们的关注点.如果我们获得了大量有助于推动正确设计的引人注目的场景,那将会有什么帮助.


此功能目前(可能)用于C#8.0.Mads谈到了在这里实施它的更多信息.

  • 太糟糕了.我只是想添加一个运算符来将TimeSpan乘以标量值...... :( (15认同)
  • 如果您有任何好消息,请在此发表评论. (5认同)
  • @SparK `^` 是 C# 中的异或运算符 (4认同)

Jor*_*dão 56

如果您控制要使用此"扩展操作符"的位置(通常使用扩展方法),您可以执行以下操作:

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

} 
Run Code Online (Sandbox Code Playgroud)

StringBuilderWrapper类声明的隐式转换运算符从一个StringBuilder 声明了期望的+运算符.通过这种方式,StringBuilder可以传递给a ReceiveImportantMessage,它将被静默转换为a StringBuilderWrapper,+可以使用运算符.

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

  private static void ReceiveImportantMessage(StringBuilder sb) {
    StringBuilderWrapper sbw = sb;
    sbw += "Hello World!";
  }
Run Code Online (Sandbox Code Playgroud)

或者,要在内联使用它的地方使用它StringBuilder,您可以简单地执行此操作:

 StringBuilder sb = new StringBuilder();
 StringBuilderWrapper sbw = sb;
 sbw += "Hello World!";
 Console.WriteLine(sb.ToString());
Run Code Online (Sandbox Code Playgroud)

我创建了一篇关于使用类似方法使其IComparable更易理解的帖子.

  • @Leon:这是这项技术的核心.我可以这样做,因为在`StringBuilderWrapper`中声明了一个[隐式转换运算符](http://msdn.microsoft.com/en-us/library/85w54y0a.aspx),这使得它成为可能. (4认同)
  • @Leon:我真的打算组成它,而不是继承它.无论如何,我不能继承它,因为它是密封的. (2认同)
  • 那么我可以建议在`String`中添加一个扩展方法:`PushIndent(".".x(4))`(也可以称为`Times`).或者也许使用这个构造函数:`PushIndent(new String('',4))`. (2认同)

Dyl*_*tie 8

目前看来这是不可能的 - 在Microsoft Connect上有一个开放的反馈问题请求这个功能:

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

建议它可能出现在将来的版本中,但不会针对当前版本实现.

  • 链接现在已经死了。 (2认同)