F# uniones discriminadas versus jerarquías de clases de C#
-
27-10-2019 - |
Pregunta
Tengo el siguiente código:
public abstract class A ...
public class B : A ...
public class C : A ...
void my_fct(A x) {
if (x is B) { block_1 }
else if (x is C) { block_2 }
else { block_3 }
}
y me pregunto si es una buena traducción de F#
type a = B | C
let my_fct x =
match x with
| B -> ( block_1 )
| C -> ( block_2 )
| _ -> ( block_3 )
??
Solución
Las uniones discriminadas de F# se corresponden bastante estrechamente con las jerarquías de clases de OO, por lo que esta es probablemente la mejor opción.La diferencia más notable es que no se pueden agregar nuevos casos a una unión discriminada sin modificar la declaración de tipo.Por otro lado, puede agregar fácilmente nuevas funciones que funcionen con el tipo (lo que corresponde aproximadamente a agregar nuevos métodos virtuales en C#).
Entonces, si no espera agregar nuevas clases heredadas (casos), esta es la mejor opción.De lo contrario, puede usar tipos de objetos de F# (u otras opciones, según el escenario).
Un punto más con respecto a su código: dado que no puede agregar nuevos casos, el compilador de F# sabe que los únicos casos que necesita son para B
y C
.Como resultado, el block_3
nunca se puede ejecutar, lo que significa que puedes escribir simplemente:
let my_fct x =
match x with
| B -> ( block_1 )
| C -> ( block_2 )
Otros consejos
sí, esto es más o menos lo mismo que hace F # de todos modos. En este caso (sin valores agregados) - F # parece traducir esto en clases para "a" y algunas etiquetas (enumeración).La clase para "a" solo tiene algunas propiedades estáticas para B y C, y algunos métodos para verificar si un objeto de tipo "a" es "B" o "C" (ver más abajo)
Pero no necesitas el caso "_ -> (block_3)", porque esto nunca puede coincidir (F # conoce todos los casos posibles y te advertirá).
Creo que es mejor si lanza una excepción en C # para este caso "más".