El C# enum es inútil.
Puede evitar la conversión desde su tipo Y restringir los valores que se pueden convertir explícitamente a su tipo realizando una clase sellada y proporcionando operadores de conversión implícita/explícita.
- Proporcione un operador implícito para convertir de su tipo a un int genérico para que no tenga que emitir.
- Proporcione un operador explícito para convertir de un int a su tipo, que arroja un error si el entero no cumple la restricción, como (int x) => (x> = 0 & & x < = 2).
Si se utiliza esta técnica, crear una clase base inmutable genérico como ConstrainedNumber<T>
, que tiene un constructor que acepta un valor de T y delegado para la restricción: delegate bool NumberConstraint<T>(T value)
. El constructor debe ejecutar el valor a través del delegado de restricción y lanzar una excepción si no cumple con la restricción. La clase base también debe encargarse de la operación de conversión implícita a T, y debe manejar la igualdad mediante la sobrecarga de object.Equals (object) y object.GetHashCode(), definiendo == y! = Operadores para el tipo ConstrainedNumber<T>
, e implementando IEquatable<T>
y IEquatable<ConstrainedNumber<T>>
. También recomiendo definir un constructor de copia para la clase base y todos los tipos derivados. La clonación se puede implementar limpiamente en la clase base recuperando el constructor de copia mediante reflexión, pero esto es completamente opcional. Puede averiguar la implementación de ConstrainedNumber<T>
usted mismo, a menos que ya la haya publicado en stackoverflow en alguna parte.
Puede proporcionar valores nominales de solo lectura estáticos en su Número restringido derivado, para que pueda acceder a ellos como una enumeración.
public sealed class ReturnValue: ConstrainedNumber<int>
{
public static readonly NumberConstraint<int> constraint = (int x) => (x >= 0 && x < 3);
public static readonly ReturnValue Success = new ReturnValue(0);
public static readonly ReturnValue FailReason1 = new ReturnValue(1);
public static readonly ReturnValue FailReason2 = new ReturnValue(2);
private ReturnValue(int value): base(value, constraint) {}
private ReturnValue(ReturnValue original): base (original) {} //may be used to support IClonable implementation in base class
public static explicit operator ReturnValue(int value)
{
switch(value) //switching to return an existing instance is more efficient than creating a new one and re-checking the constraint when there is a limited number of allowed values; if the constraint was more generic, such as an even number, then you would instead return a new instance here, and make your constructors public.
{
case 0: return Success;
case 1: return FailReason1;
case 2: return FailReason2;
}
throw new ArgumentException("Value fails to meet the constraint defined for " + typeof(ReturnValue).FullName + ".", "value");
}
}
Puede utilizar esta técnica para cualquier restricción. Por ejemplo, una clase llamada EvenNumber puede tener una restricción que devuelve verdadero si el número dado es par. En ese caso, solo haría público sus constructores y simplificaría su operador de conversión estático para que simplemente devuelva un nuevo EvenNumber, en lugar de cambiar para devolver una de las instancias existentes limitadas.
Podría ser utilizado como esto:
EvenNumber x = (EvenNumber)2;
EvenNumber y = (EvenNumber)3; //throws exception "Value fails to meet the constraint defined for {namespace}.EvenNumber." A c# enum would stupidly allow such a cast, creating an invalid EvenNumber, breaking the object-oriented model
int z = x; //implicit conversion, no cast necessary;
¡Funciona como un amuleto, gracias! Es extraño que pueda definir una enumeración: "public enum MyEnum: int {...}" y no tener sus valores implícitamente convertibles. No hay concepto de una "enumeración genérica" está allí? - enum pública MyEnum - ¿o es completamente ridículo? –
Pwninstein
Puede delcare type en su enumeración "public enum ReturnValue: int" que exige que los valores sean del tipo int. Todavía no proporciona conversión implícita. Editando para mostrar cuándo es una buena idea usar valores en una enumeración. –
Una pequeña sugerencia: use 'static readonly int' en vez de' const', en caso de que sus valores cambien en versiones futuras. No desea que las personas que llaman tengan ese valor compilado en su código. –