2012-01-19 19 views
9

Supongamos que tengo una estructura con un solo campo:¿Debo definir cada operador individual?

public struct Angle 
{ 
    public static readonly double RadiansPerDegree = Math.PI/180; 

    private readonly double _degrees; 

    public Angle(double degrees) 
    { 
     _degrees = degrees; 
    } 

    public double Degrees 
    { 
     get { return _degrees; } 
    } 

    public double Radians 
    { 
     get { return _degrees * RadiansPerDegree; } 
    } 

    public static Angle FromDegrees(double value) 
    { 
     return new Angle(value); 
    } 

    public static Angle FromRadians(double value) 
    { 
     return new Angle(value/RadiansPerDegree); 
    } 
} 

Esto funciona muy bien, hasta que yo quiero hacer cosas como esta:

var alpha = Angle.FromDegrees(90); 
var beta = Angle.FromDegrees(100); 
var inequality = alpha > beta; 
var sum = alpha + beta; 
var negation = -alpha; 
//etc. 

Por lo tanto, he implementado IEquatable<in T> y IComparable<in T>, pero que todavía no habilitó ningún operador (ni siquiera ==, <, >=, etc.).

Entonces, comencé a proporcionar sobrecargas al operador.

Por ejemplo:

public static Angle operator +(Angle a, Angle b) 
{ 
    return new Angle(a._degrees + b._degrees); 
} 

public static Angle operator -(Angle a) 
{ 
    return new Angle(-a._degrees); 
} 

public static bool operator >(Angle a, Angle b) 
{ 
    return a._degrees > b._degrees; 
} 

Esto funcionó, sin embargo, cuando miraba a todos los operadores que podría sobrecargar concebible (+, -, !, ~, ++, --, true, false, +, -, *, /, %, &, |, ^, <<, >>, ==, !=, <, >, <=, >=), empecé a sentir que tiene que haber una mejor manera. Después de todo, la estructura solo contiene un campo, y ese campo es un tipo de valor.

¿Hay alguna forma de habilitar todos los operadores de double de una sola vez? ¿O realmente tengo que escribir a mano todos los operadores que posiblemente quiera?

(Incluso si tuviera dos o tres campos, todavía me gustaría ser capaz de añadir los operadores en un lote ...)

+3

Probablemente se podría añadir a conversiones implícitas (y posiblemente de) el tipo "doble" para hacer eso. Sin embargo, algo en mi cabeza me dice que podría no ser una buena idea y podría generar ambigüedad. –

+1

Si realmente está haciendo esto solo para la conversión de grado y radian, ¿por qué no simplemente tener una clase MathHelper estática que implementa esa característica y simplemente usar doble en lugar de crear una clase que invente otra clase con un nombre diferente? –

+0

@Jeff Mercado, creo que un elenco implícito podría ser justo lo que estoy buscando, en realidad. ¿Consideraría convertir su comentario en una respuesta? Además, si realmente hay una desventaja, realmente apreciaría si pudieras expandirte un poco. Gracias. – devuxer

Respuesta

12

El punto de operadores de sobrecarga es definir cómo agregar para manipular objetos de un tipo personalizado utilizando esos operadores, por lo que si su segundo campo era una matriz de cadenas, ¿cómo esperaría que el operador ++ se implementara automáticamente? No hay una respuesta sensata, especialmente porque desconocemos el contexto del objeto o su uso, por lo que la respuesta es , sí, tiene que sobrecargar los operadores usted mismo.

Para el registro, si realmente solo necesita un campo, y es solo un doble, entonces no use una estructura en primer lugar a menos que necesite sobrecargar a los operadores para realizar alguna otra acción que no sea por predeterminado: ¡es un caso claro de exceso de ingeniería!

+0

El ejemplo de 'Angle' es una simplificación, pero mi objetivo es dejar muy claro qué son las unidades y encapsular la conversión necesaria entre unidades en un solo tipo. Entonces, si tengo un 'Ángulo', no hay ambigüedad sobre las unidades, solo tomo lo que necesito. Lo que estaba haciendo con mi pregunta era que, ojalá hubiera alguna forma de decirle al compilador que quiero que la estructura se comporte como si fuera el campo subyacente para todas las operaciones. La sugerencia de @Jeff Mercado de utilizar moldes implícitos * parece * lograr eso, pero parece preocupado de que pueda haber consecuencias no deseadas. – devuxer

+0

Tan pronto como los tipos son algo más complicados que los primitivos, entonces puede ver cómo un sistema no podría generar operaciones significativas para los datos en cuestión. ¡Al menos sabes lo que estás haciendo! Sugeriría que tal vez creas una macro en un IDE como Vim para generar todos los operadores para tus estructuras si es algo que harás más de una vez. –

+0

Creo que en todos mis casos que preveo para este proyecto en particular, puedo convertir implícitamente el tipo completo a un único tipo de valor nativo para los propósitos de realizar operaciones, pero si encuentro algo más complejo, la idea macro para generar el la sobrecarga del operador suena bien. – devuxer

0

Sí, debe definir cada operador que desee utilizar. El compilador no tiene forma de saber qué quiere que haga cada operador, además de los operadores que son negativos entre sí (e incluso esos pueden no ser necesariamente obvios; ¿y si quisiera imitar el comportamiento nulo de SQL estándar en el que == y != devolvería false en comparación con nulo?).

0

Para la mayoría de los casos, estoy de acuerdo con LaceySnr: realmente no funciona para ningún operador que devuelva su nuevo objeto (por ejemplo, +, * ect.). Para los comparadores podría funcionar (como podría haber una anotación que dice "use el valor de retorno de este método para sustituir a este objeto cuando se usa en todas las operaciones de comparación"), pero no sé nada de eso.

No estoy seguro de cuáles son las limitaciones de las anotaciones en C#, pero es posible crear una que lo haga (para los operadores que devuelven bool), pero a menos que planees usarlo mucho, dudo valdrá tu tiempo.

Habiendo dicho esto, si tuviera un objeto que tomara exactamente un argumento en el constructor, y ese argumento fuera el valor de retorno del método, debería ser posible hacerlo también.

Por supuesto que hacer nada de esto requerirá alguna clase retoques bastante extremo, que no estoy realmente en una situación de dar consejos sobre ...

Cuestiones relacionadas