繁体   English   中英

是否可以定义扩展运算符方法?

[英]Is it possible define an extension operator method?

是否可以定义同时是运算符的扩展方法? 我想要一个固定的类添加使用实际上无法应用的已知运算符的可能性。 对于这种特殊情况,我想这样做:

   somestring++;  //i really know that this string contains a numeric value

而且我不想为所有代码传播类型转换。 我知道我可以在字符串上创建包装类并定义该运算符,但我想知道这种事情是否可以避免使用 MySpecialString 搜索和替换每个字符串声明。

编辑:正如大多数人所说的字符串是密封的,所以派生是不可能的,所以我将“派生”修改为“包装器”,我的错误。

这将有用的一个明显示例是能够扩展 TimeSpan 类以包含 * 和 / 运算符。

这是理想的工作......

public static class TimeSpanHelper
{
    public static TimeSpan operator *(TimeSpan span, double factor)
    {
        return TimeSpan.FromMilliseconds(span.TotalMilliseconds * factor);
    }

    public static TimeSpan operator *(double factor, TimeSpan span)  // * is commutative
    {
        return TimeSpan.FromMilliseconds(span.TotalMilliseconds * factor);
    }

    public static TimeSpan operator /(TimeSpan span, double sections)
    {
        return TimeSpan.FromMilliseconds(span.TotalMilliseconds / factor);
    }

    public static double operator /(TimeSpan span, TimeSpan period)
    {
        return span.TotalMilliseconds / period.TotalMilliseconds);
    }

}

这在 C# 中是不可能的,但为什么不是标准的扩展方法呢?

 public static class StringExtensions {
     public static string Increment(this string s) {
          ....
     }
 }

我认为somestring.Increment()更具可读性,因为您不会让那些真的不希望看到++应用于字符串的人感到困惑。

不,不可能在课外进行。 ++运算符应在递增的类中定义。 您可以创建自己的类,该类可以从字符串转换并具有++重载,或者您可以忘记这个想法并使用常规方法。

不,你不能有一个也是操作符的扩展方法。 扩展方法只能在静态类中声明,静态类不能有实例,并且根据 C# 规范,

用户定义的运算符声明始终需要至少一个参数属于包含运算符声明的类或结构类型。 [7.3.2]

因此,扩展方法不可能也是重载运算符。

此外,您不能覆盖System.String,因为它是一个密封类。

字符串类在 C# 中是密封的,因此实际上无法创建字符串派生类。

话虽如此,扩展方法当然可以正常工作(就像助手类中的标准静态方法一样),但它不是运算符,只是通常命名的方法。

我认为您应该使用包装类,即使您可以编写扩展运算符。

//i really know that this string contains a numeric value

正是类型安全被发明的那种情况。

另一种看待它的方式是,通过编写该运算符,您已经破坏了与string类一起使用的许多其他函数和运算符,因为它们不一定保留包含数字值的属性。 通过使用包装类,而不是一个派生类中,你只有重新实现这些功能string ,对于数字字符串有意义。

我的情况与您描述的非常相似:我需要增加 Windows 窗体文本框中的文本(肯定包含一个数值)。

我理解你所描述的需求

一些字符串++; //我真的知道这个字符串包含一个数值

我的灵魂是类似的东西,我相信它与你的描述很接近

somestring =(可增加的)somestring + 1

我需要做的就是

  1. 创建名为incrementable
  2. 在其中定义一个显式运算符(以帮助将string转换为incrementable
  3. 在其中定义一个隐式运算符(以帮助将incrementable转换回string
  4. +运算符(加号)

这是我的课程完整的样子

public class incrementable
{
    public string s; // For storing string value that holds the number

    public incrementable(string _s)
    {
        s = _s;
    }

    public static explicit operator incrementable(string tmp)
    {
        return new incrementable(tmp);
    }

    public static implicit operator string(incrementable tmp)
    {
        return tmp.s;
    }

    public static incrementable operator +(incrementable str, int inc) // This will work flawlessly like `somestring = (incrementable)somestring + 1`
        => new incrementable((Convert.ToInt32(str.s) + inc).ToString());

    public static incrementable operator ++(incrementable str) // Unfortunately won't work, see below
        => new incrementable((Convert.ToInt32(str.s) + 1).ToString());
}

不幸的是,我无法通过使用一元++运算符来改进我的课程。 反对使用像((incrementable)somestring)++这样的隐式转换的原因是它会导致错误说The operand of an increment or decrement operator must be a variable, property or indexer因此不能是结果铸件。

无论如何,希望这会有所帮助!

当前不支持这是因为扩展方法是在单独的静态类中定义的,并且静态类不能具有运算符重载定义。

这都是真的,但 M$ 将来添加此功能会很好。 有时框架只是缺少一些东西,扩展可以帮助填补空白(或解决问题),这有时可以是操作符。

一个例子。 要比较 IP 地址,您必须使用 Equals 方法进行直接比较(当然也可以比较结构的一部分,也可以单独比较地址字节 - 但那是另一回事了)。 但是,使用 == 运算符总是在对象级别返回 false(即不将它们转换为字符串等)。 将 Equals 方法调用放在 == 运算符调用中有多难(这是修辞),但我们做不到。 这是不一致的,并且是错误潜入的地方(注意它不会失败,只是总是等于 false - 而 Equals 不会)。

如其他答案所示,不能直接完成。 但是如果你需要它,比如说你想改进 StringBuilder

void Main()
{
    var log = (StringBuilder)"Hello ";
    log += "World!";
    log += "\nThis example shows how to extend StringBuilder";
    log.ToString().Dump();
}

你怎么能做到这一点(即使用+运算符而不是sb.Append(str); )?


答:在这种情况下,你不能直接做,但你可以做的是:

在 DotNetFiddle 中运行它

void Main()
{
    var log = (StrBuilder)"Hello "; // same as: "Hello ".ToStrBuilder();
    log += "World!";
    log += "\nThis example shows how to extend StringBuilder";
    log.ToString().Dump();
}

public static class Extensions
{
    public static StrBuilder ToStrBuilder(this string str)
    {
        return new StrBuilder(str);
    }   
}

public class StrBuilder
{
    private StringBuilder sb;

    public StrBuilder()
    {
        sb = new StringBuilder();
    }

    public StrBuilder(string strB)
    {
        sb = new StringBuilder(strB);
    }

    public static implicit operator StrBuilder(string self)
    {
        return new StrBuilder(self);
    }

    public static StrBuilder operator +(StrBuilder sbA, string strB)
    {       
        return sbA.Append(strB);
    }

    public StrBuilder Append(string strB)
    {
        sb.Append(strB);
        return this;
    }

    public override string ToString()
    {
        return sb.ToString();
    }
}

注意:您不能从 StringBuilder 继承,因为它是一个密封类,但您可以编写一个“装箱” StringBuilder 的类 - 即这里所做的(感谢IanNorton对隐式转换的回答)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM