He estado mirando F # recientemente, y aunque no es probable que salte la valla en el corto plazo, definitivamente resalta algunas áreas donde C # (o soporte de la biblioteca) podría facilitar la vida.
En particular, estoy pensando en la capacidad de coincidencia de patrones de F #, que permite una sintaxis muy rica, mucho más expresiva que el interruptor actual / equivalentes condicionales de C #. No intentaré dar un ejemplo directo (mi F # no está a la altura), pero en resumen me permite:
- coincidencia por tipo (con comprobación de cobertura completa para uniones discriminadas) [tenga en cuenta que esto también infiere el tipo de la variable vinculada, que da acceso a los miembros, etc.]
- partido por predicado
- combinaciones de lo anterior (y posiblemente algunos otros escenarios que no conozco)
Si bien sería maravilloso que C # tomara prestada [ejem] parte de esta riqueza, mientras tanto he estado mirando lo que se puede hacer en tiempo de ejecución; por ejemplo, es bastante fácil juntar algunos objetos para permitir:
var getRentPrice = new Switch<Vehicle, int>()
.Case<Motorcycle>(bike => 100 + bike.Cylinders * 10) // "bike" here is typed as Motorcycle
.Case<Bicycle>(30) // returns a constant
.Case<Car>(car => car.EngineType == EngineType.Diesel, car => 220 + car.Doors * 20)
.Case<Car>(car => car.EngineType == EngineType.Gasoline, car => 200 + car.Doors * 20)
.ElseThrow(); // or could use a Default(...) terminator
donde getRentPrice es un Func <Vehicle, int>.
[nota: tal vez Switch / Case aquí son los términos incorrectos ... pero muestra la idea]
Para mí, esto es mucho más claro que el equivalente usando if / else repetido o un condicional ternario compuesto (que se vuelve muy desordenado para las expresiones no triviales, corchetes en abundancia). También evita una gran cantidad de conversión, y permite una extensión simple (ya sea directamente o mediante métodos de extensión) a coincidencias más específicas, por ejemplo, una coincidencia InRange (...) comparable a la VB Select ... Caso "x A y "uso.
Solo estoy tratando de evaluar si la gente piensa que hay beneficios de construcciones como las anteriores (en ausencia de soporte de idiomas).
Tenga en cuenta además que he estado jugando con 3 variantes de lo anterior:
- una versión Func <TSource, TValue> para evaluación - comparable a las declaraciones condicionales ternarias compuestas
- una versión de Action <TSource> - comparable a if / else if / else if / else if / else
- una versión de Expression <Func <TSource, TValue >> - como la primera, pero utilizable por proveedores arbitrarios de LINQ
Además, el uso de la versión basada en Expression permite la reescritura de Expression-tree, esencialmente alineando todas las ramas en una sola Expresión condicional compuesta, en lugar de usar invocación repetida. No lo he comprobado recientemente, pero en algunas de las primeras compilaciones de Entity Framework parece recordar que esto es necesario, ya que no me gustó mucho InvocationExpression. También permite un uso más eficiente con LINQ-to-Objects, ya que evita repetidas invocaciones de delegado: las pruebas muestran una coincidencia como la anterior (usando el formulario de Expresión) funcionando a la misma velocidad [marginalmente más rápido, de hecho] en comparación con el equivalente C # declaración condicional compuesta. Para completar, la versión basada en Func <...> tardó 4 veces más que la declaración condicional de C #, pero sigue siendo muy rápida y es poco probable que sea un cuello de botella importante en la mayoría de los casos de uso.
Agradezco cualquier pensamiento / entrada / crítica / etc. sobre lo anterior (o sobre las posibilidades de un soporte de lenguaje C # más rico ... aquí está la esperanza ;-p).
switch-case
declaración. No me malinterpreten, creo que tiene su lugar y probablemente buscaré una forma de implementarlo.