运算符使用C#扩展方法重载
-
05-07-2019 - |
题
我正在尝试使用扩展方法向C# StringBuilder
类添加一个operater重载。具体来说,给定 StringBuilder
sb
,我希望 sb + =" text"
等同于 sb.Append(" ;文本&QUOT。)代码>
以下是为 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
。
是否可以通过扩展方法添加运算符重载?如果是这样,那么正确的方法是什么?
解决方案
目前这不可能,因为扩展方法必须在静态类中,而静态类不能有操作符重载。
Mads Torgersen,C#语言PM说:
...对于Orcas的发布,我们决定 采取谨慎的方法并添加 只有常规的扩展方法,如 反对延伸财产, 事件,运算符,静态方法等 等常规扩展方法 我们需要LINQ,他们有 一种语法上最小的设计 一些人不可能轻易模仿 其他成员的种类。
我们越来越意识到了 其他类型的扩展成员 可能有用,所以我们会回来 在Orcas之后的这个问题。没有 但保证!
编辑:
我刚注意到,Mads在同一篇文章:
我很遗憾地报告说我们不会 在下一个版本中这样做。我们 确实非常接受扩展会员 认真地在我们的计划中,花了一个 我们付出了很多努力 对,但最终我们无法得到 它足够顺利,并决定给予 其他有趣的功能。
这仍然是我们未来的关注点 版本。如果我们得到了什么会有所帮助 大量引人注目的场景 这有助于推动正确的设计。
此功能目前已在桌面上(可能)用于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
类声明隐式转换运算符从 StringBuilder
和声明所需的 +
运算符。这样, 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());
我创建了有关使用类似方法的帖子使 IComparable
更容易理解。
目前看来这是不可能的 - 在Microsoft Connect上有一个开放的反馈问题请求这个功能:
http://connect.microsoft.com/VisualStudio/feedback/ ViewFeedback.aspx?FeedbackID = 168224
建议它可能出现在将来的版本中,但不会针对当前版本实现。
虽然不可能做操作符,但你总是可以创建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.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);
不是一般性答案,但未来寻求此类事情的求职者可能会感兴趣。
可以使用包装器和扩展来对其进行操作,但无法正确执行。你以垃圾结束,这完全违背了目的。 我在这里的某个地方有一个帖子可以做到,但它毫无价值。
顺便说一下 所有数字转换都在字符串构建器中创建需要修复的垃圾。我必须编写一个包装器,它可以工作并使用它。这值得细读。