158 votes

idée d'interrupteur / motif

J'ai été à la recherche à F# récemment, et bien que je ne suis pas susceptibles de sauter la barrière du temps, cela met en évidence certaines zones où C# (ou bibliothèque) pourrait rendre la vie plus facile.

En particulier, je suis en train de penser à propos de la correspondance de motif capacité de F#, ce qui permet une très riche de la syntaxe beaucoup plus expressive que le commutateur de courant/conditionnel C# équivalents. Je ne vais pas essayer de donner un exemple direct (ma F# n'est pas à la hauteur), mais en bref, il permet de:

  • match par type (avec la couverture de la vérification pour les victimes de syndicats) [note ce a également déduit le type de la variable liée, donnant accès membres, etc]
  • match par le prédicat
  • combinaisons de ce qui précède (et éventuellement d'autres scénarios que je ne suis pas au courant)

Alors qu'il serait agréable pour C# pour finalement emprunter [hum] une partie de cette richesse, dans l'intervalle, j'ai été la recherche de ce qui peut être fait au moment de l'exécution - par exemple, il est assez facile de frapper ensemble, certains objets afin de 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<Véhicule,int>.

[note - peut-être le Commutateur/Cas ici, c'est le mal... mais il montre que l'idée]

Pour moi, c'est beaucoup plus clair que l'équivalent de l'aide répétée si/d'autre, ou d'un composite conditionnel ternaire (qui est très salissant pour les non-trivial expressions entre parenthèses à gogo). Il permet également d'éviter un lot de casting, et permet une extension simple (que ce soit directement ou par l'intermédiaire de méthodes d'extension) de plus en plus-des rencontres spécifiques, par exemple un InRange(...) match comparable à la VB Sélectionnez...Affaire "de x À y d'utilisation".

Je suis juste en train d'évaluer si les gens pensent qu'il ya beaucoup d'avantages de constructions comme ci-dessus (en l'absence de support de la langue)?

Remarque, en outre, que j'ai joué avec 3 variantes de la ci-dessus:

  • un Func<TSource,TValue> version d'évaluation comparables pour la composition ternaire instructions conditionnelles
  • une Action<TSource> version comparable à de if/else if/else if/else if/else
  • une Expression<Func<TSource,TValue>> version - que le premier, mais utilisable par l'arbitraire fournisseurs LINQ

En outre, en utilisant l'Expression version permet l'Expression de l'arbre-la ré-écriture, essentiellement inline toutes les branches dans un composite unique Expression conditionnelle, plutôt que l'utilisation répétée d'invocation. Je n'ai pas vérifié récemment, mais dans certains début de l'Entity Framework construit me semble nécessaire, car il n'aimait pas InvocationExpression très bien. Il permet également de mieux l'utilisation de LINQ-to-Objets, car il permet d'éviter que plusieurs délégué invocations - tests montrent un match comme ci-dessus (à l'aide de la forme d'Expression) de la scène à la même vitesse [légèrement plus rapide, en fait] par rapport à l'équivalent en C# composite instruction conditionnelle. Pour être complet, le Func<...> à partir de la version 4 fois aussi long que le C# instruction conditionnelle, mais il est toujours très rapide et il est peu probable d'être un goulot d'étranglement majeur dans la plupart des cas d'utilisation.

Je souhaite la bienvenue à toutes les pensées / input / critique / etc sur le dessus (ou sur les possibilités les plus riches de C# support de la langue... en espérant qu' ;-p).

82voto

mancaus Points 2266

De Bart De Smet excellent blog a une série de 8 émissions à faire exactement ce que vous décrivez. Trouver la première partie ici.

37voto

MichaelGG Points 8202

Après avoir essayé de faire de telles "fonctionnelle" des choses en C# (et même la tentative d'un livre sur elle), je suis arrivé à la conclusion que non, à quelques exceptions près, de telles choses n'aide pas trop.

La raison principale est le fait que les langues comme F# obtenir beaucoup de leur énergie à partir de véritablement à l'appui de ces caractéristiques. Pas "vous pouvez le faire", mais "c'est simple, c'est clair, c'est prévu".

Par exemple, dans la correspondance de modèle, vous obtenez le compilateur te dire si il y a un incomplètes match ou quand un autre match ne sera jamais frappé. C'est de moins en moins utile avec une fin ouverte, mais lors de l'appariement d'une discrimination de l'union ou de n-uplets, c'est très chouette. En F#, vous vous attendez les gens à motif, et instantanément a du sens.

Le "problème" est que une fois que vous commencez à utiliser certains concepts fonctionnels, il est naturel de vouloir continuer. Cependant, en tirant parti de tuples, les fonctions partielles de l'application de méthode et de nourrissage, l'appariement de formes, de fonctions imbriquées, les génériques, les monade, etc. en C# devient très laid, très rapidement. C'est amusant, et certaines personnes très intelligentes ont fait de très chouettes choses en C#, mais en fait, à l'aide , il se sent lourd.

Ce que j'ai fini par utiliser souvent (dans l'ensemble des projets en C#:

  • Séquence de fonctions, via des méthodes d'extension pour interface IEnumerable. Des choses comme ForEach ou un Processus ("Appliquer"? -- faire une action sur une séquence élément tel qu'il est énuméré) ajustement parce que la syntaxe C# supporte bien.
  • Abstraction déclaration commune des motifs. Compliqué try/catch/finally blocs ou autres (souvent très générique) des blocs de code. L'extension LINQ-to-SQL s'inscrit dans ici aussi.
  • Les Tuples, dans une certaine mesure.

** Mais ne remarque: L'absence de généralisation automatique et l'inférence de type vraiment entraver l'utilisation de ces fonctionnalités. **

Tout cela dit, en tant que quelqu'un d'autre a mentionné, sur une petite équipe, dans un but précis, oui, peut-être qu'ils peuvent vous aider si vous êtes coincé avec le C#. Mais dans mon expérience, ils ont généralement ressentie comme plus de tracas que ce qu'ils valaient - YMMV.

Quelques autres liens:

25voto

Greg Beech Points 55270

Sans doute la raison que le C# n'est pas simple pour changer le type est parce que c'est d'abord un langage orienté objet, et la "bonne" façon de faire de l'orienté objet serait de définir un GetRentPrice méthode sur le Véhicule et de le remplacer dans les classes dérivées.

Cela dit, j'ai passé un peu de temps à jouer avec multi-paradigmes et langages fonctionnels comme F# et Haskell qui ont ce type de capacité, et je suis venu à travers un certain nombre d'endroits où il serait utile avant (par exemple, lorsque vous n'écrivez pas le types vous avez besoin pour passer sur de sorte que vous ne peut pas mettre en œuvre une méthode virtuelle sur eux) et c'est quelque chose que j'avais bienvenue dans le langage ainsi que des victimes de syndicats.

[Edit: suppression de la partie sur la performance Marc a indiqué qu'il pourrait être en court-circuit]

Un autre problème potentiel est la simplicité d'utilisation - il est clair à partir de l'appel final de ce qui se passe si le match ne parvient pas à répondre à toutes les conditions, mais qu'est-ce que le comportement si elle correspond à deux ou plusieurs de ces conditions? Faut-il lever une exception? Faut-il retourner le premier ou le dernier match?

Un moyen, j'ai tendance à l'utiliser pour résoudre ce genre de problème est d'utiliser un dictionnaire de champ avec le type de la clé et le lambda comme la valeur, ce qui est assez laconique à construire à l'aide de initialiseur d'objet de syntaxe; toutefois, cela ne représente que le type de béton et de ne pas permettre à d'autres prédicats ne peuvent donc pas être approprié pour les cas plus complexes. [Note de côté, si vous regardez à la sortie du compilateur C#, souvent elle convertit les instructions de commutation à base de dictionnaires sauter les tables, donc il ne semble pas être une bonne raison, il ne pouvait pas en charge de commutation sur les types]

23voto

Brian Points 82719

Je ne pense pas que ces sortes de bibliothèques (qui agissent comme des extensions de langage) sont susceptibles de gagner une large acceptation, mais ils sont amusants à jouer avec, et peut être très utile pour les petites équipes de travail dans des domaines spécifiques où cela est utile. Par exemple, si vous écrivez des tonnes de "règles d'entreprise/logique" qui n'type arbitraire des tests de ce genre et autres joyeusetés, je peux voir comment il serait à portée de main.

J'ai aucune idée si cela est susceptible d'être un langage C# fonction (semble douteux, mais qui peut voir l'avenir?).

Pour référence, les F# est d'environ:

let getRentPrice (v : Vehicle) = 
    match v with
    | :? Motorcycle as bike -> 100 + bike.Cylinders * 10
    | :? Bicycle -> 30
    | :? Car as car when car.EngineType = Diesel -> 220 + car.Doors * 20
    | :? Car as car when car.EngineType = Gasoline -> 200 + car.Doors * 20
    | _ -> failwith "blah"

en supposant que vous auriez défini une hiérarchie de classes le long des lignes de

type Vehicle() = class end

type Motorcycle(cyl : int) = 
    inherit Vehicle()
    member this.Cylinders = cyl

type Bicycle() = inherit Vehicle()

type EngineType = Diesel | Gasoline

type Car(engType : EngineType, doors : int) = 
    inherit Vehicle()
    member this.EngineType = engType
    member this.Doors = doors

9voto

John Leidegren Points 21951

Filtrage (comme décrit ici), son but est de déconstruire les valeurs en fonction de leur type de spécification. Cependant, le concept de classe (ou de type) en C# n'est pas d'accord avec vous.

Il y a en notant mal avec le multi-paradigme de conception de langage, au contraire, c'est très agréable d'avoir des lambdas en C#, et Haskell peut ne impératif de trucs, par exemple IO. Mais ce n'est pas très élégante, une solution, pas en Haskell de la mode.

Mais depuis séquentielle de procédure langages de programmation peuvent être compris en termes de lambda calcul, et C# qui se passe pour l'ajuster dans les paramètres d'une séquence de langage procédural, c'est un bon ajustement. Mais, en prenant quelque chose de la pure contexte fonctionnel de dire Haskell, puis le mettre dans une langue qui n'est pas pur, eh bien, ce que fait, ne garantit pas un meilleur résultat.

Mon point est ceci, ce qui rend la correspondance de motif tique est liée à la langue de conception et de modèle de données. Cela dit, je ne crois pas que la correspondance de motif pour être une fonction utile de C#, car elle ne permet pas de résoudre typique C# problèmes ni ne cadrent bien avec l'impératif paradigme de programmation.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X