2011-04-01 13 views
11

¿es posible definir un método de extensión que al mismo tiempo es un operador? Quiero una clase fija, agrego la posibilidad de usar un operador conocido que realmente no se puede aplicar. Para este caso particular, yo quiero hacer esto:¿Es posible definir un método de operador de extensión?

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

Y no quiero difundir tipos de conversiones para todo el código. Sé que podría crear una clase de contenedor sobre una cadena y definir ese operador, pero quiero saber si este tipo de cosas es posible para evitar buscar y reemplazar cada declaración de cadena con MySpecialString.

Editado: como la mayoría dice que la cadena está sellada, por lo que la derivación no es posible, entonces modifico "derivada" a "envoltorio", error mío.

+0

Ver [esto] (http://stackoverflow.com/questions/172658/operator-overloading-with-c-extension-methods/172666#172666) respuesta: "Esto no es posible en la actualidad, debido a los métodos de extensión debe estar en clases estáticas, y las clases estáticas no pueden tener sobrecargas de operadores ". – rsenna

+0

:(lo veo pero como fue escrito en 2008 tuve la esperanza de que las cosas hayan cambiado – mjsr

Respuesta

4

No, no es posible hacerlo desde fuera de la clase. El operador ++ se debe definir dentro de la clase que se está incrementando. Puede crear su propia clase que sea convertible de cadena y tendrá una sobrecarga de ++ o puede olvidarse de esta idea y usar métodos regulares.

1

Actualmente esto no se admite porque los métodos de extensión se definen en clases estáticas separadas y las clases estáticas no pueden tener definiciones de sobrecarga de operadores.

8

Eso no es posible en C#, pero ¿por qué no un método de extensión estándar?

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

creo somestring.Increment() es aún más fácil de leer, ya que no está confundiendo las personas que realmente no esperan ver ++ aplicada a una cadena.

+0

Gracias consejos. :) – mjsr

2

La clase de cadena está sellada en C#, por lo que la creación de una clase derivada de cadena en realidad no es posible.

Dicho esto, un método de extensión, por supuesto, funcionará bien (al igual que un método estático estándar en una clase de ayuda) pero no será un operador, solo el método de nombre común.

5

No, no puede tener un método de extensión que también sea un operador. Los métodos de extensión sólo pueden ser declaradas en las clases estáticas, que no pueden tener casos y de conformidad con la especificación C#,

definidos por el usuario declaraciones operador siempre requieren por lo menos uno de los parámetros a ser del tipo de clase o estructura que contiene la declaración del operador. [7.3.2]

Por lo tanto, es imposible que un método de extensión sea también un operador sobrecargado.

Además, no puede anular System.String ya que es una clase sealed.

1

Esto es todo cierto, pero sería bueno para M $ agregar esta funcionalidad en el futuro. A veces, el marco simplemente le falta algo y una extensión puede ayudar a cerrar la brecha (o solucionar el problema), esto a veces puede ser un operador.

Un ejemplo. Para comparar las direcciones IP, debe usar el método Equals para comparar directamente (por supuesto, las partes de la estructura también podrían compararse como lo podrían hacer los bytes de direcciones individualmente, pero esa es otra historia). Sin embargo, usar el operador == siempre devuelve falso en el nivel del objeto (es decirsin convertirlos a cadenas, etc.). ¿Qué tan difícil es poner la llamada al método Equals dentro de la llamada al operador == (eso es retórico), pero no podemos hacerlo. Esto es inconsistente y es un lugar donde los errores se infiltran (tenga en cuenta que no falla, siempre equivale a falso, mientras que Iguales no).

1

Yo diría que usted debería usar una clase contenedora, incluso si pudiera escribir un operador de extensión.

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

es exactamente el tipo de situación para la que se inventó la seguridad de tipo.

Otra forma de verlo es que al escribir ese operador, ha roto muchas otras funciones y operadores que trabajan con la clase string, ya que no necesariamente conservan la propiedad de contener un valor numérico. Al utilizar una clase contenedora, no una clase derivada, solo vuelve a implementar las características de string que tienen sentido para las cadenas numéricas.

5

Un claro ejemplo de dónde esto sería útil es poder extender la clase TimeSpan para incluir los operadores * y /.

Esto es lo que lo ideal sería trabajar ...

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

} 
+1

De hecho. Hacer math timespan con muchos .Multiply() .Divide() etc se convierte rápidamente en feo –

+0

Lo intento y obtengo "las clases estáticas no pueden contener operadores definidos por el usuario"; si no es estático, entonces obtengo "uno de los parámetros de un operador binario" la sobrecarga debe ser del tipo que lo contiene " – Felype

0

yo estaba en una situación muy similar a la que ha descrito: lo que necesitaba para aumentar el texto (que contiene un valor numérico para el seguro) en un cuadro de texto de Windows Forms .

entiendo su necesidad como usted la describe

somestring ++; // lo que realmente sé que esta cadena contiene un valor numérico

Mi soultion es algo así que creo que está cerca de su descripción

somestring = (incrementable) somestring + 1

Todo lo que tenía que hacer era clase

  1. creación llama incrementable
  2. definir un operador explícita en ella (para ayudar a convertir string a incrementable)
  3. definir un operador implícito en ella (para ayudar a convertir incrementable de nuevo a string)
  4. operador para + (signo más)

Aquí es como mi clase se ve en completa

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

por desgracia no pude conseguir logrado i Mejorar mi clase mediante el uso del operador único ++. La razón en contra del uso de la conversión implícita como ((incrementable)somestring)++ es que va a dar como resultado un error que dice The operand of an increment or decrement operator must be a variable, property or indexer por lo que no puede ser el resultado de esa conversión.

De todos modos, ¡espero que esto ayude!

Cuestiones relacionadas