Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/269.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 是否可以定义扩展运算符方法?_C#_.net_Operator Overloading_Operators_Extension Methods - Fatal编程技术网

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

C# 是否可以定义扩展运算符方法?,c#,.net,operator-overloading,operators,extension-methods,C#,.net,Operator Overloading,Operators,Extension Methods,是否可以定义一个同时也是运算符的扩展方法? 我想为一个固定类添加一个可能性,即使用一个实际上无法应用的已知运算符。 对于这种特殊情况,我想这样做: somestring++; //i really know that this string contains a numeric value 我不想为所有代码传播类型转换。 我知道我可以在一个字符串上创建包装器类并定义那个操作符,但我想知道这种事情是否可以避免搜索并用MySpecialString替换每个字符串声明 编辑:大多数人都说字符

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

   somestring++;  //i really know that this string contains a numeric value
我不想为所有代码传播类型转换。 我知道我可以在一个字符串上创建包装器类并定义那个操作符,但我想知道这种事情是否可以避免搜索并用MySpecialString替换每个字符串声明


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

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

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

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

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

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

字符串类是用C#密封的,所以创建一个字符串派生类实际上是不可能的


也就是说,扩展方法当然可以很好地工作(就像helper类中的标准静态方法一样),但它不是一个操作符,只是一个通常命名的方法。

不,您不能有一个扩展方法同时也是一个操作符。扩展方法只能在静态类中声明,静态类不能有实例,根据C#spec

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

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

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

此外,由于它是一个类,所以不能重写。

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

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

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

//i really know that this string contains a numeric value
这正是发明类型安全性的目的


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

一个明确的例子是,可以扩展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);
    }

}

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

我理解你所描述的需要

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

我的想法和你的描述很接近

somestring=(可递增)somestring+1

我所需要做的就是

  • 创建名为
    incrementable
  • 在其中定义显式运算符(以帮助将
    字符串
    转换为
    可增量
  • 在其中定义隐式运算符(以帮助将可递增的
    转换回
    字符串
  • +
    运算符(加号)
  • 下面是我的课堂完整的样子

    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)+
    )的原因是,它将导致错误,即
    递增或递减运算符的操作数必须是变量、属性或索引器
    ,因此不能是该转换的结果


    无论如何,希望这有帮助

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

    void Main()
    {
        var log = (StringBuilder)"Hello ";
        log += "World!";
        log += "\nThis example shows how to extend StringBuilder";
        log.ToString().Dump();
    }
    
    如何实现这一点(即使用
    +
    运算符而不是
    sb.Append(str);


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

    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的类-也就是说,这里做了什么(由于涉及隐式转换)。

    请参阅答案:“这在目前是不可能的,因为扩展方法必须在静态类中,并且静态类不能有运算符重载。”:(我看到了,但正如2008年写的那样,我希望事情确实发生了变化。用大量的.Multiply().Divide()等做时间跨度数学很快就会变得丑陋