Ho esaminato F # di recente e, sebbene non sia probabile che salti presto la recinzione, evidenzia sicuramente alcune aree in cui C # (o il supporto della libreria) potrebbe semplificare la vita.
In particolare, sto pensando alla capacità di corrispondenza dei pattern di F #, che consente una sintassi molto ricca, molto più espressiva dell'attuale switch / equivalenti C # condizionali. Non proverò a fare un esempio diretto (il mio F # non è all'altezza), ma in breve permette:
- abbina per tipo (con verifica della copertura completa per i sindacati discriminati) [nota che questo influisce anche sul tipo per la variabile associata, dando accesso ai membri ecc.]
- partita per predicato
- combinazioni di quanto sopra (e forse alcuni altri scenari di cui non sono a conoscenza)
Mentre sarebbe bello per C # eventualmente prendere in prestito [ahem] parte di questa ricchezza, nel frattempo ho visto cosa si può fare in fase di esecuzione - ad esempio, è abbastanza facile mettere insieme alcuni oggetti per consentire:
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
dove getRentPrice è un Func <Veicolo, int>.
[nota - forse Switch / Case qui sono i termini sbagliati ... ma mostra l'idea]
Per me, questo è molto più chiaro dell'equivalente usando ripetuto if / else, o un condizionale ternario composito (che diventa molto caotico per le espressioni non banali - parentesi a bizzeffe). Evita anche un sacco di casting e consente una semplice estensione (direttamente o tramite metodi di estensione) a corrispondenze più specifiche, ad esempio una corrispondenza InRange (...) paragonabile a VB Select ... Caso "x To y "utilizzo.
Sto solo cercando di valutare se la gente pensa che ci siano molti benefici da costrutti come sopra (in assenza di supporto linguistico)?
Nota inoltre che ho giocato con 3 varianti di cui sopra:
- una versione Func <TSource, TValue> per la valutazione - paragonabile alle dichiarazioni condizionali ternarie composte
- una versione Action <TSource> - paragonabile a if / else if / else if / else if / else
- una versione di Express <Func <TSource, TValue >> - come la prima, ma utilizzabile da provider LINQ arbitrari
Inoltre, l'utilizzo della versione basata su Expression consente di riscrivere l'albero di Expression, fondendo essenzialmente tutti i rami in una singola espressione condizionale composita, piuttosto che utilizzare ripetute invocazioni. Non ho verificato di recente, ma in alcune build di Entity Framework sembra ricordare che ciò sia necessario, poiché InvocationExpression non è piaciuto molto. Inoltre, consente un utilizzo più efficiente con LINQ-to-Objects, poiché evita ripetute invocazioni dei delegati: i test mostrano una corrispondenza come quella sopra (utilizzando il modulo Espressione) che si comporta alla stessa velocità [marginalmente più veloce, in effetti] rispetto all'equivalente C # istruzione condizionale composita. Per completezza, la versione basata su Func <...> ha impiegato 4 volte più dell'istruzione condizionale C #, ma è ancora molto rapida ed è improbabile che rappresenti un grosso collo di bottiglia nella maggior parte dei casi d'uso.
Accolgo con favore qualsiasi pensiero / input / critica / ecc. Su quanto sopra (o sulle possibilità di un supporto linguistico C # più ricco ... ecco sperando ;-p).
switch-case
dichiarazione. Non fraintendetemi, penso che abbia il suo posto e probabilmente cercherò un modo per implementare.