En un lanzamiento reciente del podcast DotNet & More Blazor, NetCore 3.0 Preview, C # 8 y no solo mencionamos casualmente un tema tan candente como C # 8. La historia sobre la experiencia con C # 8 no fue lo suficientemente grande como para dedicarle un tema por separado, por lo que se decidi贸 compartir con ella los medios del g茅nero epistolar.
En este art铆culo, me gustar铆a hablar sobre mi experiencia de usar C # 8 en producci贸n durante 4 meses. A continuaci贸n puede encontrar respuestas a las siguientes preguntas:
- C贸mo "deletrear" en el nuevo C #
- Qu茅 caracter铆sticas fueron realmente 煤tiles
- Que decepcionado
Puede encontrar una lista completa de las caracter铆sticas de C # 8 en la documentaci贸n oficial de Microsoft . En este art铆culo, omitir茅 aquellas oportunidades que no podr铆a probar por una raz贸n u otra, a saber:
- Miembros de solo lectura
- Miembros de interfaz predeterminados
- Estructuras de referencia desechables
- Flujos asincr贸nicos
- 脥ndices y rangos
Propongo comenzar con una de las posibilidades m谩s deliciosas, como me pareci贸 antes.
Cambiar expresiones
En nuestros sue帽os, presentamos esta funci贸n muy optimista:
int Exec(Operation operation, int x, int y) => operation switch { Operation.Summ => x + y, Operation.Diff => x - y, Operation.Mult => x * y, Operation.Div => x / y, _ => throw new NotSupportedException() };
Pero, desafortunadamente, la realidad hace sus propios ajustes.
En primer lugar, no hay posibilidad de combinar las condiciones:
string TrafficLights(Signal signal) { switch (signal) { case Signal.Red: case Signal.Yellow: return "stop"; case Signal.Green: return "go"; default: throw new NotSupportedException(); } }
En la pr谩ctica, esto significa que en la mitad de los casos, la expresi贸n del interruptor tendr谩 que convertirse en un interruptor regular para evitar copiar y pegar.
En segundo lugar, la nueva sintaxis no admite declaraciones, es decir c贸digo que no devuelve un valor. Parecer铆a, bueno, y no es necesario, pero yo mismo me sorprend铆 cuando me di cuenta de la frecuencia con la que se usa el interruptor (junto con la coincidencia de patrones) para una afirmaci贸n en las pruebas.
En tercer lugar, la expresi贸n switch, que se desprende del 煤ltimo p谩rrafo, no admite manejadores de l铆neas m煤ltiples. Qu茅 miedo entendemos al momento de agregar los registros:
int ExecFull(Operation operation, int x, int y) { switch (operation) { case Operation.Summ: logger.LogTrace("{x} + {y}", x, y); return x + y; case Operation.Diff: logger.LogTrace("{x} - {y}", x, y); return x - y; case Operation.Mult: logger.LogTrace("{x} * {y}", x, y); return x * y; case Operation.Div: logger.LogTrace("{x} / {y}", x, y); return x / y; default: throw new NotSupportedException(); } }
No quiero decir que el nuevo interruptor es malo. No, 茅l es bueno, simplemente no lo suficientemente bueno.
Propiedad y patrones posicionales
Hace un a帽o, me parec铆an los principales candidatos para el t铆tulo de "oportunidad que cambi贸 el desarrollo". Y, como se esperaba, para utilizar todo el poder de los patrones posicionales y de propiedad, debe cambiar su enfoque de desarrollo. Es decir, es necesario imitar los tipos de datos algebraicos.
Parece que cu谩l es el problema: toma la interfaz del marcador y listo. Desafortunadamente, este m茅todo tiene un serio inconveniente en un proyecto grande: nadie garantiza el seguimiento en tiempo de dise帽o de la expansi贸n de sus tipos algebraicos. Por lo tanto, es muy probable que con el tiempo, los cambios en el c贸digo conduzcan a muchos "fallos en el incumplimiento" en los lugares m谩s inesperados.
Patrones de tuplas
Pero el "hermano menor" de las nuevas posibilidades de comparaci贸n con la muestra demostr贸 ser realmente bien hecho. La cuesti贸n es que el patr贸n de tupla no requiere ning煤n cambio en la arquitectura familiar de nuestro c贸digo, simplemente simplifica algunos casos:
Player? Play(Gesture left, Gesture right) { switch (left, right) { case (Gesture.Rock, Gesture.Rock): case (Gesture.Paper, Gesture.Paper): case (Gesture.Scissors, Gesture.Scissors): return null; case (Gesture.Rock, Gesture.Scissors): case (Gesture.Scissors, Gesture.Paper): case (Gesture.Paper, Gesture.Rock): return Player.Left; case (Gesture.Paper, Gesture.Scissors): case (Gesture.Rock, Gesture.Paper): case (Gesture.Scissors, Gesture.Rock): return Player.Right; default: throw new NotSupportedException(); } }
Pero la mejor parte es que esta caracter铆stica, que es bastante predecible, funciona muy bien con el m茅todo Deconstruct. Simplemente pase una clase con Deconstruct implementado para cambiar y usar las capacidades del patr贸n de tupla.
Usando declaraciones
Parecer铆a una oportunidad menor, pero trae mucha alegr铆a. En todas las promociones, Microsoft habla sobre un aspecto como reducir la anidaci贸n. Pero seamos honestos, no tanto lo que importa. Pero lo realmente serio son los efectos secundarios de excluir un bloque de c贸digo:
- A menudo, al agregar el uso, tenemos que extraer el c贸digo "dentro" del bloque usando el m茅todo de copiar y pegar. Ahora simplemente no lo pensamos
- Las variables declaradas dentro del uso y usadas despu茅s de Eliminar el objeto que usa son un verdadero dolor de cabeza. Un problema menos
- En las clases que requieren llamadas frecuentes de Dispose, cada m茅todo ser铆a 2 l铆neas m谩s largo. Parecer铆a un poco, pero en la condici贸n de muchos m茅todos peque帽os, este poco no permite mostrar una cantidad suficiente de estos m茅todos en una pantalla
Como resultado, algo tan simple como usar declaraciones cambia la sensaci贸n de codificaci贸n tanto que simplemente no desea volver a c # 7.3.
Funciones locales est谩ticas
Para ser honesto, si no fuera por la ayuda del an谩lisis de c贸digo, ni siquiera notar铆a esta posibilidad. Sin embargo, se estableci贸 firmemente en mi c贸digo: despu茅s de todo, las funciones locales est谩ticas son perfectamente adecuadas para el papel de peque帽as funciones puras, ya que no pueden soportar el cierre de las variables del m茅todo. Como resultado, es m谩s f谩cil para el coraz贸n, porque comprende que hay un error potencial menos en su c贸digo.
Tipos de referencia anulables
Y para el postre, me gustar铆a mencionar la caracter铆stica m谩s importante de C # 8. En verdad, el an谩lisis de tipos de referencia anulables merece un art铆culo separado. Solo quiero describir las sensaciones.
Resumen
Por supuesto, las oportunidades presentadas no alcanzan una revoluci贸n completa, pero cada vez hay menos brecha entre C # y F # / Scala. Ya sea bueno o malo, el tiempo lo dir谩.
En el momento del lanzamiento de este art铆culo, C # 8 puede que ya se haya asentado en su proyecto, por lo que me pregunto, 驴qu茅 siente sobre la nueva versi贸n de nuestro idioma favorito?