开发者

Is it possible define an extension operator method?

开发者 https://www.devze.com 2023-02-21 04:17 出处:网络
is it possible to define an extension method that at the same time is an operator? I want for a fixed class add the开发者_如何转开发 possibility to use a known operator that actually can\'t be applied

is it possible to define an extension method that at the same time is an operator? I want for a fixed class add the开发者_如何转开发 possibility to use a known operator that actually can't be applied. For this particular case i want to do this:

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

And i don't want to spread types conversions for all the code. I know that i could create wrapper class over an string and define that operator but i want to know if this kind of thing is possible to avoid search-and-replace every string declaration with MySpecialString.

Edited: as most have say string is sealed, so derivation isn't possible, so i modify "derived" to "wrapper", my mistake.


That is not possible in C#, but why not a standard extension method?

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

I think somestring.Increment() is even more readable, as you're not confusing people who really dont expect to see ++ applied to a string.


A clear example of where this would be useful is to be able to extend the TimeSpan class to include * and / operators.

This is what would ideally work...

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);
    }

}


No, it is not possible to do from outside of the class. ++ operator should be defined inside class which is being incremented. You can either create your own class which will be convertible from string and will have ++ overload or you can forget about this idea and use regular methods.


No, you can't have an extension method which is also an operator. Extension methods can only be declared in static classes, which can't have instances and according to the C# spec,

User-defined operator declarations always require at least one of the parameters to be of the class or struct type that contains the operator declaration. [7.3.2]

Therefore, it is impossible for an extension method to also be an overloaded operator.

Additionally, you can't override System.String since it is a sealed class.


The string class is sealed in C#, so creating a string-derived class actually isn't possible.

That being said, an extension method will of course work just fine (as will a standard static method in a helper class) but it won't be an operator, just ordinarily-named method.


Currently this is not supported because Extension methods are defined in separate static class and static classes cannot have operator overloading definitions.


This is all true, but it would be nice for M$ to add this functionality in the future. Sometimes the framework is just missing things and an extension can help plug the gap (or fix the issue) this can sometimes be operators.

An example. To compare IP Addresses, you must use the Equals method to directly compare (of course parts of the struct could also be compared as could the address bytes individually - but that's another story). However, using the == operator always returns false at the object level (i.e. without converting them to strings etc). How hard is it to put the Equals method call inside the == operator call (that's rhetorical), but we can't do it. This is inconsistant and a place for bugs to creep in (note it does not fail, just always equates to false - whereas Equals does not).


I would argue that you should use a wrapper class, even if you could write an extension operator.

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

is exactly the sort of situation that type-safety was invented for.

Another way of looking at it is that by writing that operator, you have broken many other functions and operators that work with the string class, since they don't necessarily preserve the property of containing a numeric value. By using a wrapper class, not a derived class, you only re-implement those features of string that make sense for numeric strings.


i was in a very similar situation as you described: i needed to increase the text (containing a numeric value for sure) in a Windows Forms textbox.

I understand your need as you described

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

My soultion is something like that which i believe is close to your description

somestring = (incrementable)somestring + 1

All i needed to do was

  1. creating class called incrementable
  2. defining an explicit operator in it (to aid converting string to incrementable )
  3. defining an implicit operator in it (to aid converting incrementable back to string )
  4. operator for + (plus sign)

Here's how my class looks in complete

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());
}

Unfortunately i just couldn't get managed to improve my class by the usage of unary ++ operator. The reason against of usage of implicit conversion like ((incrementable)somestring)++ is that it is going to result in error saying The operand of an increment or decrement operator must be a variable, property or indexer hence can not be result of that casting.

Anyway, hope this helps!


As shown in the other answers, it cannot be done directly. But what if you need it, say you want to improve StringBuilder like

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

how can you achieve this (i.e. use + operator instead of sb.Append(str);) ?


Answer: In this case, you can't do it directly, but what you can do is:

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();
    }
}

Note: You can't inherit from StringBuilder because it is a sealed class, but you can write a class that "boxes" a StringBuilder - which is, what is done here (thanks to IanNorton's answer regarding implicit conversion).

0

精彩评论

暂无评论...
验证码 换一张
取 消