2008-11-15 30 views
29

A diferencia de C++, en C# no puede sobrecargar el operador de asignación.¿Hay alguna solución para sobrecargar el operador de asignación en C#?

Estoy haciendo una clase numérica personalizada para operaciones aritméticas con números muy grandes y quiero que tenga la apariencia de los tipos numéricos incorporados como int, decimal, etc. He sobrecargado el operadores aritméticos, pero sigue siendo la tarea ...

He aquí un ejemplo:

Number a = new Number(55); 
Number b = a; //I want to copy the value, not the reference 

¿hay una solución para ese problema?

+2

explicar el tema (por qué lo necesita). – Shog9

+0

Lo siento, tal vez debería haber sido más específico. Estoy haciendo una clase numérica personalizada para operaciones aritméticas con números muy grandes y quiero que tenga la apariencia de los tipos numéricos incorporados como int, decimal, etc. He sobrecargado los operadores aritméticos, pero la tarea se mantiene ... –

+0

Gracias: he agregado su comentario a la pregunta en sí. – Shog9

Respuesta

26

Todavía no tengo claro para nada que realmente lo necesite. O bien:

  • Su tipo de número debe ser una estructura (lo que es probable, los números son el ejemplo más común de estructuras). Tenga en cuenta que todos los tipos que desea que su tipo actúe (int, decimal, etc.) son estructuras.

o:

  • Su tipo de Número debe ser inmutable, por lo que todas las operaciones de mutación devolver una nueva instancia, en cuyo caso no es necesario que los datos se copian en la asignación de todos modos. (De hecho, tu tipo debe ser inmutable sea o no una estructura. Las estructuras mutables son malas, y un número ciertamente no debe ser un tipo de referencia mutable.)
+0

Sí, tal vez la idea de estructura es buena. Y me gusta la opción de inmutabilidad, se sugirió en otra respuesta. Gracias, intentaré lo que propongas. –

+1

Las estructuras mutables pueden ser malas, pero el equipo C# pensó que estaban bien para los Enumeradores. Creo que es más correcto decirlo como una regla general. –

+3

La capacidad de reproducción no es mala, si puede evitar el intercambio de objetos. Esto puede hacerse implementando tipos lineales que requieren alguna forma de sobrecarga de asignación. http://en.wikipedia.org/wiki/Linear_type_system. – cdiggins

6

No podrá evitar que tenga el aspecto de C++, ya que a = b; tiene otra semántica en C++ que en C#. En C#, a = b; hace un punto al mismo objeto como b. En C++, a = b cambia el contenido de a. Ambos tienen sus altibajos. Es como lo hace

MyType * a = new MyType(); 
MyType * b = new MyType(); 
a = b; /* only exchange pointers. will not change any content */ 

En C++ (que perderá la referencia al primer objeto, y crear una pérdida de memoria. Pero vamos a ignorar que aquí). No puede sobrecargar el operador de asignación en C++ para eso tampoco.

La solución es fácil:

MyType a = new MyType(); 
MyType b = new MyType(); 

// instead of a = b 
a.Assign(b); 

exención de responsabilidad: No soy un desarrollador de C#

Se puede crear un sólo escritura-propiedad como esta. luego haz a.Self = b; encima.

public MyType Self { 
    set { 
     /* copy content of value to this */ 
     this.Assign(value); 
    } 
} 

Ahora, esto es no buena. Ya que viola el principio de la menor sorpresa (POLS). Uno no esperaría que cambiara si uno hace a.Self = b;

+0

Quizás podría hacerlo de esa manera.Pero lo que quise decir fue: una solución que me da la apariencia real de la sobrecarga del operador de asignación, así que literalmente puedo decir: MyType a = new MyType(); MyType b = new MyType(); a = b; y realiza alguna lógica de asignación personalizada. –

+0

La descripción de por qué no funciona es puntual. Sin embargo, como sugiere, la idea de propiedad del Self no es tan buena, – Charlie

+0

"En C++, a = b cambia el contenido de a". - Eso no es del todo correcto. depende de si a y b son punteros o no. a = b podría hacer un punto para b o podría llamar a su = sobrecarga y copiar el contenido en a. – MickyD

3

En lugar de hacer una copia de los datos al pasar la referencia, puede hacer que la clase sea inmutable. Cuando la clase es inmutable, tener múltiples referencias a ella no es un problema ya que no se puede cambiar.

Las operaciones que cambian los datos, por supuesto, devolverán nuevas instancias.

+0

¡Esa es una buena idea! Gracias, lo intentaré! –

42

puede utilizar la palabra clave 'implícito' para crear una sobrecarga para los servicios:

Suponga que tiene un tipo como Foo, que se siente es implícitamente convertible de una cadena. Se podría escribir el siguiente método estático en su clase Foo:

public static implicit operator Foo(string normalString) 
{ 
    //write your code here to go from string to Foo and return the new Foo. 
} 

Una vez hecho esto, a continuación, puede utilizar el siguiente en el código:

Foo x = "whatever"; 
+2

Genial, esto responde una pregunta que iba a hacer;) –

+3

¿No funciona solo si está tratando de asignar un tipo a otro? Es un elenco implícito, después de todo. No creo que eso ayude si quisieras asignar 'Number' a' Number'. –

+0

@Jonathan Wood - ¡Eso era exactamente lo que estaba buscando! ¡Muy apreciado! –

2

un post anterior sugiere lo siguiente:

operador implícito estático público Foo (string normalString) {}

Probé este enfoque ... pero para que funcione necesita esto:

operador implícita public static Foo (Foo originales) {}

y el compilador no le permitirá tener una función de conversión implícita de su tipo exacto, ni de ningún tipo base de usted mismo. Eso tiene sentido ya que sería una forma de puerta trasera de anular el operador de asignación, que C# no quiere permitir.

+0

"La palabra clave implícita se usa para declarar un operador implícito de conversión de tipo definido por el usuario. Úselo para habilitar conversiones implícitas entre un tipo definido por el usuario y otro tipo, ..." - MSDN – MickyD

0

Aquí es una solución que funcionó para mí:

public class MyTestClass 
{ 
    private int a; 
    private string str; 

    public MyTestClass() 
    { 
     a = 0; 
     str = null; 
    } 

    public MyTestClass(int a, string str) 
    { 
     this.a = a; 
     this.str = str; 
    } 

    public MyTestClass Clone 
    { 
     get 
     { 
     return new MyTestClass(this.a, this.str); 
     } 
    } 
} 

En algún otro lugar en el código:

MyTestClass test1 = new MyTestClass(5, "Cat"); 
MyTestClass test2 = test1.Clone; 
Cuestiones relacionadas