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

时间:2011-04-01 20:27:42

标签: c# operators operator-overloading extension-methods

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

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

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

编辑:因为大多数人都说字符串是密封的,所以推导是不可能的,所以我将“derived”修改为“wrapper”,我的错误。

10 个答案:

答案 0 :(得分:8)

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

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

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

答案 1 :(得分:5)

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

答案 2 :(得分:5)

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

  

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

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

此外,您无法覆盖System.String,因为它是sealed类。

答案 3 :(得分:5)

这个有用的明显例子是能够将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);
    }

}

答案 4 :(得分:2)

字符串类用C#密封,因此创建一个字符串派生类实际上不可能

话虽这么说,扩展方法当然可以正常工作(正如帮助类中的标准静态方法一样),但它不是操作符,只是通常命名的方法。

答案 5 :(得分:1)

目前不支持此方法,因为扩展方法是在单独的静态类中定义的,而静态类不能包含操作符重载定义。

答案 6 :(得分:1)

这一切都是正确的,但M $将来添加此功能会很不错。有时框架只是缺少的东西,扩展可以帮助填补空白(或解决问题)这有时可能是运营商。

一个例子。要比较IP地址,必须使用Equals方法直接进行比较(当然,结构的某些部分也可以与地址字节单独进行比较 - 但这是另一个故事)。但是,使用==运算符始终在对象级别返回false(即,不将它们转换为字符串等)。将Equals方法调用置于==运算符调用中是多么困难(这是修辞),但我们不能这样做。这是不一致的,也是一个容易陷入错误的地方(注意它不会失败,只是总是等于假 - 而等于不等)。

答案 7 :(得分:1)

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

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

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

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

答案 8 :(得分:0)

我处于与你描述的情况非常相似的情况:我需要在Windows窗体文本框中增加文本(确保包含数值)。

我理解你所描述的需要

  

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

我的灵魂就像我认为接近你的描述

  

somestring =(可递增)somestring + 1

我需要做的只是

  1. 创建名为incrementable
  2. 的类
  3. 在其中定义显式运算符(以帮助将string转换为incrementable
  4. 在其中定义隐式运算符(以帮助将incrementable转换回string
  5. +的操作符(加号)
  6. 以下是我的班级完整的看法

    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,因此不能成为该转换的结果。

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

答案 9 :(得分:0)

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

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

您如何实现此目标(即使用+而不是sb.Append(str);)?


答案: 在这种情况下,您不能直接执行操作,但是可以执行以下操作:

Run it in 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继承,因为它是一个密封的类,但是您可以编写一个将BoxBuilder“装箱”的类-也就是说,这里要做的(感谢{ {3}}关于隐式转换)。