F # discriminava unioni rispetto alle gerarchie di classi C #
-
27-10-2019 - |
Domanda
Ho il seguente codice:
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 }
}
e mi chiedo se sia una buona traduzione da F #
type a = B | C
let my_fct x =
match x with
| B -> ( block_1 )
| C -> ( block_2 )
| _ -> ( block_3 )
??
Soluzione
Le unioni discriminate in F # corrispondono abbastanza strettamente alle gerarchie di classi OO, quindi questa è probabilmente l'opzione migliore.La differenza più notevole è che non è possibile aggiungere nuovi casi a un'unione discriminata senza modificare la dichiarazione del tipo.D'altra parte, puoi facilmente aggiungere nuove funzioni che funzionano con il tipo (che corrisponde grosso modo all'aggiunta di nuovi metodi virtuali in C #).
Quindi, se non ti aspetti di aggiungere nuove classi (case) ereditate, questa è l'opzione migliore.Altrimenti, puoi usare i tipi di oggetto F # (o altre opzioni, a seconda dello scenario).
Un altro punto sul codice: poiché non è possibile aggiungere nuovi casi, il compilatore F # sa che gli unici casi di cui hai bisogno sono B
e C
.Di conseguenza, block_3
non può mai essere eseguito, il che significa che puoi scrivere solo:
let my_fct x =
match x with
| B -> ( block_1 )
| C -> ( block_2 )
Altri suggerimenti
sì, questo è più o meno lo stesso di F # comunque. In questo caso (nessun valore aggiunto) - F # sembra tradurlo in classi a per "a" e alcuni tag (enumerazione).La classe per "a" ha solo alcune proprietà statiche per B e C e alcuni metodi per verificare se un oggetto di tipo "a" è "B" o "C" (vedi sotto)
Ma non hai bisogno del caso "_ -> (block_3)", perché questo non può mai essere trovato (F # conosce tutti i casi possibili e ti avviserà).
Penso che sia meglio se lanci un'eccezione in C # per questo caso "else".