Reflétant Nom du paramètre: l'abus des expressions C # lambda ou la brillance de syntaxe?

StackOverflow https://stackoverflow.com/questions/1718037

Question

Je suis à la recherche à la MvcContrib composant Grid et je suis fasciné, mais en même temps repoussé, par une astuce syntaxique utilisé dans la syntaxe de grille :

.Attributes(style => "width:100%")

La syntaxe ci-dessus définit l'attribut style du code HTML généré à width:100%. Maintenant, si vous faites attention, le « style » est nulle part spécifié, est déduit du nom du paramètre dans l'expression! Je devais creuser cette question et trouvé où la « magie » se produit:

Hash(params Func<object, TValue>[] hash)
{
    foreach (var func in hash)
    {
        Add(func.Method.GetParameters()[0].Name, func(null));
    }
}

En effet, le code utilise le formel, la compilation, le nom de paramètres pour créer le dictionnaire des attributs paires nom-valeur. La construction de la syntaxe est très expressif résultat en effet, mais en même temps très dangereux. L'utilisation générale des expressions lambda permet de remplacer des noms utilisés sans effet secondaire. Je vois un exemple dans un livre qui dit collection.ForEach(book => Fire.Burn(book)) Je sais que je peux écrire dans mon code collection.ForEach(log => Fire.Burn(log)) et cela signifie la même chose . Mais avec la syntaxe Grille MvcContrib ici tout d'un coup, je trouve un code qui recherche activement et prend des décisions sur la base des noms que je choisis pour mes variables!

Alors est-ce une pratique courante avec la communauté 3.5 / C # 4.0 et les expressions lambda amoureux? Ou est un franc-tireur astuce voyou Je ne devrais pas inquiéter?

Était-ce utile?

La solution

Ce pauvre a Interop. Par exemple, considérez ceci C # - F # exemple

C #:

public class Class1
{
    public static void Foo(Func<object, string> f)
    {
        Console.WriteLine(f.Method.GetParameters()[0].Name);
    }
}

F #:

Class1.Foo(fun yadda -> "hello")

Résultat:

"arg" est imprimé (et non "bla").

Par conséquent, les concepteurs de la bibliothèque doivent soit éviter ce genre de « abus », ou bien au moins fournir une surcharge « standard » (par exemple, qui prend le nom de chaîne comme un paramètre supplémentaire) s'ils veulent avoir une bonne Interop à travers. langues net.

Autres conseils

Je trouve que pas tant bizarre à cause de la nom , mais parce que le lambda est inutile ; il pourrait utiliser un type anonyme et être plus souple:

.Attributes(new { style = "width:100%", @class="foo", blip=123 });

Ceci est un modèle utilisé dans une grande partie de ASP.NET MVC (par exemple), et a d'autres utilisations (a mise en garde , notez

Je voulais juste jeter à mon avis (je suis l'auteur de la composante de grille de MvcContrib).

est sans aucun doute l'abus langue - sans aucun doute à ce sujet. Cependant, je ne vraiment considérer contre-intuitif - lorsque vous regardez un appel à Attributes(style => "width:100%", @class => "foo")
Je pense qu'il est assez évident ce qui se passe (Il est certainement pas pire que l'approche de type anonyme). Du point de vue de IntelliSense, je suis d'accord, il est assez opaque.

Pour les personnes intéressées, quelques informations de base sur son utilisation dans MvcContrib ...

a ajouté à la grille comme une préférence personnelle - je n'aime pas l'utilisation des types anonymes comme des dictionnaires (ayant un paramètre qui prend « objet » est tout aussi opaque que celui qui prend params Func []) et le Dictionnaire collection initialiseur est assez bavard (je suis pas fan d'interfaces couramment verbeux, par exemple avoir à enchaîner plusieurs appels à un attribut ( « style »,. « display: none ») Attribut ( « classe », « toto ») etc )

Si C # a une syntaxe moins verbeux pour littéraux dictionnaire, je ne l'aurais pas pris la peine, y compris cette syntaxe dans la composante de grille:)

Je tiens également à souligner que l'utilisation de ce dans MvcContrib est totalement facultatif - ce sont des méthodes d'extension surchargeant wrap qui prennent une place IDictionary. Je pense qu'il est important que si vous fournissez une méthode comme cela, vous devez également soutenir une approche plus « normale », par exemple pour Interop avec d'autres langues.

En outre, quelqu'un a mentionné la «tête de réflexion et je voulais simplement souligner qu'il n'y a vraiment pas grand-chose d'une tête avec cette approche - il n'y a pas de compilation de réflexion d'exécution ou de l'expression en cause (voir http://blog.bittercoder.com/PermaLink,guid,206e64d1-29ae-4362 -874b-83f5b103727f.aspx ).

Je préférerais

Attributes.Add(string name, string value);

Il est beaucoup plus explicite et standard et rien est gagné en utilisant lambdas.

Bienvenue à Rails Terrain:)

Il n'y a vraiment rien de mal avec elle aussi longtemps que vous savez ce qui se passe. (Il est quand ce genre de chose n'est pas documenté bien qu'il ya un problème).

L'ensemble du cadre Rails est construit sur l'idée de la convention sur la configuration. choses nommer une certaine touches comme vous dans une convention qu'ils utilisent et vous obtenez beaucoup de fonctionnalités gratuitement. À la suite de la convention de nommage vous emmène là où vous allez plus vite. Le tout fonctionne à merveille.

Un autre endroit où je l'ai vu un truc comme ça est dans les assertions d'appel de méthode dans Moq. Vous passez dans un lambda, mais le lambda est jamais exécuté. Ils utilisent simplement l'expression pour vous assurer que l'appel de méthode est passé et jeter une exception sinon.

horribles sur plus d'un niveau. Et non, ce n'est rien comme Ruby. Il est un abus de C # et .Net.

Il y a eu de nombreuses suggestions sur la façon de le faire d'une manière plus avant droit: tuples, types anonymes, une interface fluide et ainsi de suite.

Qu'est-ce qui le rend si mauvais est que sa juste façon de fantaisie pour son propre bien:

  • Qu'est-ce qui se passe quand vous avez besoin d'appeler cela de VB?

    .Attributes(Function(style) "width:100%")

  • Son complètement contre-intuitif, IntelliSense fournira peu d'aide à trouver comment passer des choses dans.

  • Son inutilement inefficace.

  • Personne n'aura aucune idée de la façon de le maintenir.

  • Quel est le type de l'argument allant dans les attributs, est-il Func<object,string>? Comment cette intention révélatrice. Quelle est votre documentation IntelliSense va dire: « S'il vous plaît ne pas tenir compte de toutes les valeurs de l'objet »

Je pense que vous êtes tout à fait justifié d'avoir ces sentiments de révulsion.

Je suis dans le camp « brillance syntaxe », si elles documentent clairement, et il semble paniquer ce cool, il n'y a presque pas de problème avec elle imo!

Les deux. Il est abusage des expressions lambda brillance de la syntaxe.

Je suis tombé sur presque jamais ce genre d'utilisation. Je pense qu'il est "inapproprié":)

Ce n'est pas une façon courante d'utilisation, il est incompatible avec les conventions générales. Ce type de syntaxe a des avantages et des inconvénients bien sûr:

Contre

  • Le code n'est pas intuitive (conventions habituelles sont différentes)
  • Il a tendance à être fragile (nouveau nom de paramètre cassera la fonctionnalité).
  • Il est un peu plus difficile à tester (faire semblant de l'API nécessitera l'utilisation de la réflexion dans les tests).
  • Si l'expression est utilisée de manière intensive ce sera plus lent en raison de la nécessité d'analyser le paramètre et non seulement la valeur (coût de réflexion)

Plus

  • Il est plus facile à lire après le développeur adapté à cette syntaxe.

Bottom line -. Dans la conception de l'API publique j'aurais choisi de façon plus explicite

Non, il est certainement pas pratique courante. Il est contre-intuitif, il n'y a aucun moyen de regarder juste le code pour savoir ce qu'il fait. Vous devez savoir comment il est utilisé pour comprendre comment il est utilisé.

Au lieu de fournir des attributs en utilisant un réseau de délégués, les méthodes seraient plus claires CHAÎNAGE et de meilleures performances:

.Attribute("style", "width:100%;").Attribute("class", "test")

Bien que ce soit un peu plus à taper, il est clair et intuitif.

Puis-je utiliser pour paraphraser une expression?

magic lambda (n):. Une fonction lambda utilisée uniquement dans le but de remplacer une chaîne magique

Quel est le problème avec les éléments suivants:

html.Attributes["style"] = "width:100%";

Tout cela rodomontades sur « horridness » est un groupe de gars de longue date c # réagissent de manière excessive (et je suis un long temps programmeur C # et encore un très grand fan de la langue). Il n'y a rien d'horrible cette syntaxe. Il est simplement une tentative de rendre la syntaxe ressemble plus à ce que vous essayez d'exprimer. Moins « bruit » il y a dans la syntaxe pour quelque chose, plus le programmeur peut le comprendre. La diminution du bruit dans une ligne de code aide seulement un peu, mais laisser qui s'accumulent dans de plus en plus de code, et il se révèle être un avantage substantiel.

Ceci est une tentative de l'auteur de lutter pour les mêmes avantages que vous donner de DSL - lorsque le code juste « ressemble à » ce que vous essayez de dire, vous avez atteint un lieu magique. Vous pouvez discuter si cela est bon pour Interop, ou si elle est assez agréable que les méthodes anonymes pour justifier une partie des coûts de « complexité ». Juste assez ... donc dans votre projet, vous devez faire le bon choix de l'opportunité d'utiliser ce type de syntaxe. Mais quand même ... cela est une tentative intelligente par un programmeur pour faire ce que, à la fin de la journée, nous essayons tous de faire (que nous le réalisions ou non). Et ce que nous essayons tous de faire, est la suivante: «Dites à l'ordinateur ce que nous voulons faire dans un langage qui est aussi proche que possible de la façon dont nous pensons à ce qu'il doit faire »

Se rapprocher de l'expression de nos instructions aux ordinateurs de la même manière que nous pensons à l'interne une clé pour rendre le logiciel plus maintenable et plus précis.

EDIT: Je l'avais dit « la clé pour rendre le logiciel plus maintenable et plus précis », qui est un peu exagéré crazily naïf de unicorniness. Je l'ai changé pour « une clé. »

Ceci est l'un des avantages des arbres d'expression - on peut examiner le code lui-même pour des informations supplémentaires. C'est ainsi .Where(e => e.Name == "Jamie") peut être converti en SQL équivalent clause Where. Ceci est une utilisation intelligente des arbres d'expression, bien que j'espère que cela ne va pas plus loin que cela. Quelque chose de plus complexe est susceptible d'être plus difficile que le code qu'il espère remplacer, donc je suppose que ce sera autolimitée.

Il est une approche intéressante. Si vous contraint le côté droit de l'expression à des constantes que vous pouvez mettre en œuvre en utilisant

Expression<Func<object, string>>

Ce qui je pense est ce que vous voulez vraiment la place du délégué (vous utilisez le lambda pour obtenir les noms des deux côtés)     Voir la mise en œuvre naïve ci-dessous:

public static IDictionary<string, string> Hash(params Expression<Func<object, string>>[] hash) {
    Dictionary<string, string> values = new Dictionary<string,string>();
    foreach (var func in hash) {
        values[func.Parameters[0].Name] = ((ConstantExpression)func.Body).Value.ToString();
    }
    return values;
}

Cela pourrait même répondre aux préoccupations Interop interlangage qui a été mentionné plus haut dans le fil.

Le code est très intelligent, mais il provoque potentiellement plus de problèmes qu'il résout.

Comme vous l'avez dit, il y a maintenant une dépendance obscure entre le nom du paramètre (style) et un attribut HTML. Aucune vérification de compilation est fait. Si le nom du paramètre est mal orthographié, la page ne sera probablement pas un message d'erreur d'exécution, mais beaucoup plus difficile à trouver bug logique (pas d'erreur, mais un comportement incorrect).

Une meilleure solution serait d'avoir un membre de données qui peut être vérifié au moment de la compilation. Ainsi, au lieu de ceci:

.Attributes(style => "width:100%");

code avec une propriété de style pourrait être vérifiée par le compilateur:

.Attributes.Style = "width:100%";

ou même:

.Attributes.Style.Width.Percent = 100;

C'est plus de travail pour les auteurs du code, mais cette approche tire parti de la capacité de contrôle de type de C #, ce qui aide à prévenir les bugs d'entrer dans le code en premier lieu.

en effet son semble comme Ruby =), au moins pour moi l'utilisation d'une ressource statique pour une « recherche » dynamique plus tard ne correspond pas à des considérations de conception api, espérons que cette astuce est facultatif dans ce api.

On peut hériter de IDictionary (ou non) et de fournir un indexeur qui se comporte comme un tableau php lorsque vous ne avez pas besoin d'ajouter une clé pour définir une valeur. Ce sera une utilisation valable de la sémantique .net c # non seulement, et encore besoin de documentation.

espérons que cette aide

à mon humble avis, il est une façon cool de le faire. Nous aimons tous le fait que la nomination d'un contrôleur de classe fera un contrôleur droit MVC? Donc, il y a des cas où la désignation est importante.

En outre l'intention est très claire ici. Il est très facile de comprendre que .Attribute( book => "something") se traduira par book="something" et .Attribute( log => "something") entraînera log="something"

Je suppose que ce ne devrait pas être un problème si vous le traiter comme une convention. Je suis d'avis que ce qui vous fait écrire moins de code et fait l'intention évidente est une bonne chose.

À mon avis, il est l'abus du lambdas.

Quant à la syntaxe brillance je trouve style=>"width:100%" simple confusion. Particularily en raison de la => au lieu de =

Si la méthode noms (Func) sont bien choisis, cela est une excellente manière d'éviter les maux de tête d'entretien (ex: ajouter une nouvelle Func, mais il a oublié d'ajouter à la liste de mappage fonction paramètres). Bien sûr, vous devez documenter fortement et vous feriez mieux d'être auto-générer la documentation pour les paramètres de la documentation pour les fonctions de cette classe ...

Je pense que c'est pas mieux que « les chaînes magiques ». Je ne suis pas un grand fan des types anonymes soit pour cela. Il a besoin d'une meilleure et fortement typé approche.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top