He estado pensando en crear tipos personalizados para identificadores como este:
public enum CustomerId : int { /* intentionally empty */ }
public enum OrderId : int { }
public enum ProductId : int { }
Mi motivación principal para esto es evitar el tipo de error en el que accidentalmente pasa un orderItemId a una función que esperaba un orderItemDetailId.
Parece que las enumeraciones funcionan a la perfección con todo lo que quisiera usar en una aplicación web .NET típica:
- El enrutamiento MVC funciona bien
- La serialización JSON funciona bien
- Cada ORM que se me ocurra funciona bien
Así que ahora me pregunto, "¿por qué no debería hacer esto?" Estos son los únicos inconvenientes que se me ocurren:
- Puede confundir a otros desarrolladores.
- Introduce inconsistencias en su sistema si tiene identificadores no integrales.
- Puede requerir fundición adicional, como
(CustomerId)42
. Pero no creo que esto sea un problema, ya que el enrutamiento ORM y MVC generalmente le entregará valores del tipo de enumeración directamente.
Entonces mi pregunta es, ¿qué me estoy perdiendo? Esta es probablemente una mala idea, pero ¿por qué?
Respuestas:
Es una gran idea crear tipos para cada tipo de identificador, principalmente por las razones que usted indicó. No lo haría implementando el tipo como enum porque hacerlo una estructura o clase adecuada le brinda más opciones:
Puede leer sobre la implementación de esto en el artículo Funcional C #: obsesión primitiva .
fuente
Es un truco inteligente, pero aún así un truco en el que se abusa de una característica para algo que no es el propósito previsto. Los hacks tienen un costo en mantenimiento, por lo que no es suficiente con que no pueda encontrar otros inconvenientes, también debe tener beneficios significativos en comparación con la forma más idiomática de resolver el mismo problema.
La forma idiomática sería crear un tipo de envoltura o estructura con un solo campo. Esto le dará la misma seguridad de tipo de una manera más explícita e idiomática. Si bien su propuesta es ciertamente inteligente, no veo ninguna ventaja significativa al usar tipos de contenedor.
fuente
Desde mi punto de vista, la idea es buena. La intención de dar diferentes tipos a clases de identificadores no relacionados, y de lo contrario expresar la semántica a través de tipos y dejar que el compilador lo compruebe, es buena.
No sé cómo funciona en .NET en cuanto al rendimiento, por ejemplo, los valores de enumeración están necesariamente encuadrados. El código OTOH que funciona con una base de datos es probable que esté vinculado a E / S de todos modos y los identificadores en caja no serán un cuello de botella.
En un mundo perfecto, los identificadores serían inmutables y solo comparables para la igualdad; bytes reales serían un detalle de implementación. Los identificadores no relacionados tendrían tipos incompatibles, por lo que no podría usar uno por otro por error. Su solución prácticamente se ajusta a la factura.
fuente
No puede hacer esto, las enumeraciones deben estar predefinidas. Por lo tanto, a menos que esté dispuesto a predefinir todo el espectro de posibles valores de ID de cliente, su tipo será inútil.
Si lanzas, estarías desafiando tu objetivo principal de evitar asignar accidentalmente una identificación de tipo A a una identificación de tipo B. Entonces las enumeraciones no son útiles para su propósito.
Sin embargo, esto plantea la pregunta de si sería útil crear sus tipos para la identificación del cliente, la identificación del pedido y la identificación del producto descendiendo desde Int32 (o Guid). Puedo pensar en una razón por la cual esto estaría mal.
El propósito de una identificación es la identificación. Los tipos integrales ya son perfectos para esto, ya no se identifican más al descender de ellos. No se requiere ni se desea especialización, su mundo no se representará mejor al tener diferentes tipos de identificadores. Entonces, desde una perspectiva OO, sería malo.
Con su sugerencia, desea algo más que seguridad de tipo, desea seguridad de valor y eso está más allá del dominio de modelado, es un problema operativo.
fuente
public ActionResult GetCustomer(CustomerId custId)
no se necesita ninguna conversión : el marco MVC proporcionará el valor.