J'ai regardé F # récemment, et bien que je ne sois pas susceptible de sauter la clôture de si tôt, cela met définitivement en évidence certains domaines où C # (ou le support de la bibliothèque) pourrait rendre la vie plus facile.
En particulier, je pense à la capacité de correspondance de modèle de F #, qui permet une syntaxe très riche - beaucoup plus expressive que le commutateur actuel / les équivalents C # conditionnels. Je n'essaierai pas de donner un exemple direct (mon F # n'est pas à la hauteur), mais en bref cela permet:
- correspondance par type (avec vérification de la couverture complète pour les unions discriminées) [notez que cela déduit également le type de la variable liée, donnant l'accès aux membres, etc.]
- correspondance par prédicat
- combinaisons de ce qui précède (et peut-être d'autres scénarios dont je ne suis pas au courant)
Alors qu'il serait bien que C # emprunte éventuellement [ahem] une partie de cette richesse, dans l'intervalle, j'ai examiné ce qui peut être fait au moment de l'exécution - par exemple, il est assez facile d'assembler certains objets pour permettre:
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
où getRentPrice est un Func <Vehicle, int>.
[note - peut-être que Switch / Case est ici les mauvais termes ... mais cela montre l'idée]
Pour moi, c'est beaucoup plus clair que l'équivalent en utilisant if / else répété, ou un conditionnel ternaire composite (qui devient très compliqué pour les expressions non triviales - des crochets à gogo). Cela évite également beaucoup de cast, et permet une simple extension (soit directement, soit via des méthodes d'extension) à des correspondances plus spécifiques, par exemple une correspondance InRange (...) comparable au VB Select ... Case "x To y "utilisation.
J'essaie juste de déterminer si les gens pensent qu'il y a beaucoup d'avantages à des constructions comme celles-ci (en l'absence de support linguistique)?
Notez en outre que j'ai joué avec 3 variantes de ce qui précède:
- une version Func <TSource, TValue> pour l'évaluation - comparable aux instructions conditionnelles ternaires composites
- une version Action <TSource> - comparable à if / else if / else if / else if / else
- une version Expression <Func <TSource, TValue >> - comme la première, mais utilisable par des fournisseurs LINQ arbitraires
De plus, l'utilisation de la version basée sur les expressions permet la réécriture de l'arborescence des expressions, en incorporant essentiellement toutes les branches dans une seule expression conditionnelle composite, plutôt que d'utiliser des appels répétés. Je n'ai pas vérifié récemment, mais dans certaines premières versions d'Entity Framework, je semble me souvenir que cela était nécessaire, car il n'aimait pas beaucoup InvocationExpression. Il permet également une utilisation plus efficace avec LINQ-to-Objects, car il évite les invocations répétées de délégués - les tests montrent une correspondance comme celle ci-dessus (en utilisant le formulaire Expression) fonctionnant à la même vitesse [légèrement plus rapide, en fait] par rapport à l'équivalent C # instruction conditionnelle composite. Par souci d'exhaustivité, la version basée sur Func <...> a pris 4 fois plus de temps que l'instruction conditionnelle C #, mais elle est toujours très rapide et ne sera probablement pas un goulot d'étranglement majeur dans la plupart des cas d'utilisation.
J'apprécie toute réflexion / entrée / critique / etc sur ce qui précède (ou sur les possibilités d'un support plus riche du langage C # ... ici en espérant ;-p).
switch-case
déclaration. Ne vous méprenez pas, je pense qu'il a sa place et je chercherai probablement un moyen de le mettre en œuvre.