当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《运算符使用C#扩展方法重载》经验,为你挑选了3个好方法。

我正在尝试使用扩展方法向C#StringBuilder类添加一个operater重载.具体来说,给定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在此上下文中不允许使用关键字.

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



1> Jacob Krall..:

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

Mads Torgersen,C#语言PM说:

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

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

编辑:

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

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

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


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


太糟糕了.我只是想添加一个运算符来将TimeSpan乘以标量值...... :(
如果您有任何好消息,请在此发表评论.

2> Jordão..:

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

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可以传递给a ReceiveImportantMessage,它将被静默转换为a StringBuilderWrapper,+可以使用运算符.

为了使这个事实对调用者更透明,你可以声明ReceiveImportantMessage为a 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更易理解的帖子.


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

3> Dylan Beatti..:

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

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

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

推荐阅读
linjiabin43
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有