Je regarde le composant MvcContrib Grid et je suis fasciné, mais en même temps repoussé, par une astuce syntaxique utilisée dans la syntaxe Grid :
.Attributes(style => "width:100%")
La syntaxe ci-dessus définit l'attribut style du code HTML généré sur width:100%
. Maintenant, si vous faites attention, le «style» n'est spécifié nulle part. Il est déduit du nom du paramètre dans l'expression! J'ai dû creuser cela et j'ai trouvé où la «magie» se produisait:
Hash(params Func<object, TValue>[] hash)
{
foreach (var func in hash)
{
Add(func.Method.GetParameters()[0].Name, func(null));
}
}
Donc, en effet, le code utilise le nom formel de l'heure de compilation des paramètres pour créer le dictionnaire des paires nom-valeur d'attribut. La construction de syntaxe résultante est certes très expressive, mais en même temps très dangereuse.
L'utilisation générale des expressions lambda permet de remplacer les noms utilisés sans effet secondaire. Je vois un exemple dans un livre qui dit que 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 de la grille MvcContrib ici, tout d'un coup, je trouve du code qui regarde activement et prend des décisions en fonction des noms que je choisis pour mes variables!
Est-ce donc une pratique courante avec la communauté C # 3.5 / 4.0 et les amoureux des expressions lambda? Ou est-ce un franc-tireur un truc dont je ne devrais pas m'inquiéter?
la source
Réponses:
Cela a une mauvaise interop. Par exemple, considérons cet exemple C # - F #
C #:
F#:
Résultat:
"arg" est imprimé (pas "yadda").
Par conséquent, les concepteurs de bibliothèques doivent soit éviter ces types d'abus, soit au moins fournir une surcharge `` standard '' (par exemple, qui prend le nom de chaîne comme paramètre supplémentaire) s'ils souhaitent avoir une bonne interopérabilité entre les langues .Net.
la source
Je trouve cela étrange non pas tant à cause du nom , mais parce que le lambda n'est pas nécessaire ; il pourrait utiliser un type anonyme et être plus flexible:
C'est un modèle utilisé dans une grande partie d'ASP.NET MVC (par exemple), et a d' autres utilisations (une mise en garde , notez également les pensées d'Ayende si le nom est une valeur magique plutôt que spécifique à l'appelant)
la source
HtmlAttributes
classe avec les attributs attendus (pour intellisense), et ignorer ceux qui ont desnull
valeurs ...Je voulais juste jeter à mon avis (je suis l'auteur du composant de grille MvcContrib).
Il s'agit certainement d'un abus de langage - sans aucun doute. Cependant, je ne le considérerais pas vraiment comme contre-intuitif - lorsque vous regardez un appel à,
Attributes(style => "width:100%", @class => "foo")
je pense que ce qui se passe est assez évident (ce n'est certainement pas pire que l'approche de type anonyme). D'un point de vue intellisense, je suis d'accord que c'est assez opaque.
Pour ceux qui sont intéressés, quelques informations générales sur son utilisation dans MvcContrib ...
J'ai ajouté cela à la grille comme préférence personnelle - je n'aime pas l'utilisation de types anonymes comme dictionnaires (avoir un paramètre qui prend "object" est tout aussi opaque que celui qui prend params Func []) et l'initialiseur de la collection Dictionary est plutôt verbeux (je ne suis pas non plus un fan des interfaces fluides, par exemple avoir à enchaîner plusieurs appels à un attribut ("style", "affichage: aucun"). Attribut ("classe", "foo") etc)
Si C # avait une syntaxe moins verbeuse pour les littéraux de dictionnaire, je n'aurais pas pris la peine d'inclure cette syntaxe dans le composant de grille :)
Je tiens également à souligner que l'utilisation de ceci dans MvcContrib est complètement facultative - ce sont des méthodes d'extension qui enveloppent les surcharges qui prennent un IDictionary à la place. Je pense qu'il est important que si vous fournissez une méthode comme celle-ci, vous souteniez également une approche plus «normale», par exemple pour l'interopérabilité avec d'autres langues.
De plus, quelqu'un a mentionné la `` surcharge de réflexion '' et je voulais juste souligner qu'il n'y a vraiment pas beaucoup de surcharge avec cette approche - il n'y a pas de réflexion d'exécution ou de compilation d'expression impliquée (voir http://blog.bittercoder.com /PermaLink,guid,206e64d1-29ae-4362-874b-83f5b103727f.aspx ).
la source
je préférerais
C'est beaucoup plus explicite et standard et rien n'est gagné en utilisant des lambdas.
la source
html.Attributes.Add("style", "width:100%");
ne lit pas aussi bien questyle = "width:100%"
(le HTML réel généré), alors qu'ilstyle => "width:100%"
est très proche de ce à quoi il ressemble dans le HTML résultant.Bienvenue chez Rails Land :)
Il n'y a vraiment rien de mal à cela tant que vous savez ce qui se passe. (C'est lorsque ce genre de chose n'est pas bien documenté qu'il y a un problème).
L'intégralité du framework Rails repose sur l'idée d'une convention sur la configuration. Nommer les choses d'une certaine manière vous fait entrer dans une convention qu'ils utilisent et vous obtenez gratuitement de nombreuses fonctionnalités. Le respect de la convention de dénomination vous permet d'atteindre votre destination plus rapidement. Le tout fonctionne à merveille.
Un autre endroit où j'ai vu une astuce comme celle-ci est dans les assertions d'appels de méthode dans Moq. Vous passez un lambda, mais le lambda n'est jamais exécuté. Ils utilisent simplement l'expression pour s'assurer que l'appel de méthode a eu lieu et lèvent une exception sinon.
la source
C'est horrible à plus d'un niveau. Et non, cela n'a rien à voir avec Ruby. C'est un abus de C # et .NET.
Il y a eu de nombreuses suggestions sur la façon de le faire de manière plus simple: tuples, types anonymes, une interface fluide et ainsi de suite.
Ce qui le rend si mauvais, c'est que c'est juste un moyen de s'imaginer pour son propre bien:
Que se passe-t-il lorsque vous devez appeler cela à partir de Visual Basic?
.Attributes(Function(style) "width:100%")
C'est complètement contre-intuitif, et intellisense fournira peu d'aide pour comprendre comment transmettre des choses.
C'est inutilement inefficace.
Personne ne saura comment le maintenir.
Quel est le type d'argument entrant dans les attributs? est-ce
Func<object,string>
? Comment cette intention est-elle révélatrice? Que va dire votre documentation intellisense, "Veuillez ignorer toutes les valeurs de l'objet"?Je pense que vous avez tout à fait raison d'avoir ces sentiments de répulsion.
la source
Je suis dans le camp de la "brillance syntaxique", s'ils le documentent clairement et que ça a l'air vraiment cool, il n'y a presque aucun problème avec ça imo!
la source
Les deux. C'est un abus des expressions lambda ET de la brillance de la syntaxe.
la source
Je n'ai presque jamais rencontré ce genre d'utilisation. Je pense que c'est "inapproprié" :)
Ce n'est pas un mode d'utilisation courant, il est incompatible avec les conventions générales. Ce type de syntaxe a bien sûr des avantages et des inconvénients:
Les inconvénients
Avantages
Conclusion - dans la conception de l'API publique, j'aurais choisi une méthode plus explicite.
la source
Non, ce n'est certainement pas une pratique courante. C'est contre-intuitif, il n'y a aucun moyen de simplement regarder le code pour comprendre ce qu'il fait. Vous devez savoir comment il est utilisé pour comprendre comment il est utilisé.
Au lieu de fournir des attributs à l'aide d'un tableau de délégués, les méthodes de chaînage seraient plus claires et fonctionneraient mieux:
Bien que ce soit un peu plus à taper, c'est clair et intuitif.
la source
.Attribute("style", "width:100%")
me donnestyle="width:100%"
, mais pour autant que je sache, cela pourrait me donnerfoooooo
. Je ne vois pas la différence.Puis-je l'utiliser pour inventer une phrase?
lambda magique (n): une fonction lambda utilisée uniquement dans le but de remplacer une chaîne magique.
la source
Quel est le problème avec les éléments suivants:
la source
Toute cette diatribe sur "horreur" est un groupe de gars c # de longue date exagérant (et je suis un programmeur C # de longue date et toujours un très grand fan du langage). Il n'y a rien d'horrible dans cette syntaxe. C'est simplement une tentative de faire ressembler la syntaxe à ce que vous essayez d'exprimer. Moins il y a de «bruit» dans la syntaxe de quelque chose, plus le programmeur peut le comprendre facilement. Réduire le bruit dans une seule ligne de code n'aide que peu, mais laissez cela s'accumuler dans de plus en plus de code, et cela s'avère être un avantage substantiel.
Il s'agit d'une tentative de l'auteur de viser les mêmes avantages que les DSL vous offrent - lorsque le code "ressemble" à ce que vous essayez de dire, vous avez atteint un endroit magique. Vous pouvez débattre de savoir si cela est bon pour l'interopérabilité, ou si c'est assez plus agréable que les méthodes anonymes pour justifier une partie du coût de la «complexité». Assez juste ... donc dans votre projet, vous devez faire le bon choix d'utiliser ou non ce type de syntaxe. Mais quand même ... c'est une tentative intelligente d'un programmeur pour faire ce que, en fin de compte, nous essayons tous de faire (que nous le réalisions ou non). Et ce que nous essayons tous de faire, c'est ceci: "Dites à l'ordinateur ce que nous voulons qu'il fasse dans un langage aussi proche que possible de la façon dont nous pensons à ce que nous voulons qu'il fasse."
Se rapprocher de l'expression de nos instructions aux ordinateurs de la même manière que nous pensons en interne est une clé pour rendre les logiciels plus faciles à maintenir et plus précis.
EDIT: J'avais dit "la clé pour rendre les logiciels plus faciles à maintenir et plus précis", ce qui est un peu exagérément naïf de licorne. Je l'ai changé en "une clé".
la source
C'est l'un des avantages des arborescences d'expression - on peut examiner le code lui-même pour des informations supplémentaires. C'est ainsi que l'
.Where(e => e.Name == "Jamie")
on peut convertir la clause SQL Where équivalente. C'est une utilisation intelligente des arbres d'expression, mais j'espère que cela ne va pas plus loin. Tout ce qui est plus complexe sera probablement plus difficile que le code qu'il espère remplacer, donc je soupçonne qu'il se limitera automatiquement.la source
C'est une approche intéressante. Si vous avez contraint le côté droit de l'expression à être des constantes uniquement, vous pouvez implémenter à l'aide de
Ce que je pense est ce que vous voulez vraiment au lieu 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:
Cela pourrait même répondre au problème d'interopérabilité entre les langues qui a été mentionné plus tôt dans le fil.
la source
Le code est très intelligent, mais il provoque potentiellement plus de problèmes qu'il résout.
Comme vous l'avez souligné, il existe maintenant une dépendance obscure entre le nom du paramètre (style) et un attribut HTML. Aucune vérification du temps de compilation n'est effectuée. Si le nom du paramètre est mal tapé, la page n'aura probablement pas de message d'erreur d'exécution, mais un bug logique beaucoup plus difficile à trouver (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. Donc au lieu de ça:
le code avec une propriété Style peut être vérifié par le compilateur:
ou même:
C'est plus de travail pour les auteurs du code, mais cette approche tire parti de la forte capacité de vérification de type de C #, qui aide à empêcher les bogues d'entrer dans le code en premier lieu.
la source
en effet, cela ressemble à Ruby =), au moins pour moi, l'utilisation d'une ressource statique pour une "recherche" dynamique ultérieure ne convient pas aux considérations de conception d'api, espérons que cette astuce est facultative dans cette api.
Nous pourrions hériter d'IDictionary (ou non) et fournir un indexeur qui se comporte comme un tableau php lorsque vous n'avez pas besoin d'ajouter une clé pour définir une valeur. Ce sera une utilisation valide de la sémantique .net, pas seulement c #, et il faudra toujours de la documentation.
J'espère que cela t'aides
la source
À mon avis, c'est un abus des lambdas.
En ce qui concerne l'éclat de la syntaxe, je trouve tout
style=>"width:100%"
simplement déroutant. Particulièrement à cause de la=>
place de=
la source
À mon humble avis, c'est une façon cool de le faire. Nous aimons tous le fait que nommer un contrôleur de classe en fera un contrôleur dans MVC, n'est-ce pas? Il y a donc des cas où la dénomination est importante.
L'intention est également très claire ici. Il est très facile de comprendre que
.Attribute( book => "something")
cela entraînerabook="something"
et.Attribute( log => "something")
entraîneralog="something"
Je suppose que cela ne devrait pas être un problème si vous le traitez comme une convention. Je suis d'avis que tout ce qui vous fait écrire moins de code et rend l'intention évidente est une bonne chose.
la source
Si les noms de méthode (func) sont bien choisis, alors c'est une excellente façon d'éviter les maux de tête de maintenance (c'est-à-dire: ajouter un nouveau func, mais j'ai oublié de l'ajouter à la liste de mappage des paramètres de fonction). Bien sûr, vous devez le documenter fortement et vous feriez mieux de générer automatiquement la documentation des paramètres à partir de la documentation des fonctions de cette classe ...
la source
Je pense que ce n'est pas mieux que des "cordes magiques". Je ne suis pas non plus très fan des types anonymes pour cela. Il a besoin d'une approche meilleure et fortement typée.
la source