2009-02-19 5 views
1

Il y a quelque temps j'ai dû adresser un certain problème de conception de C# quand je mettais en application un cadre de génération de code de Javascript. L'une des solutions que j'ai trouvées consistait à utiliser le mot-clé "using" d'une manière totalement différente (hackish, if you please). Je l'ai utilisé comme une syntaxe de sucre (enfin, à l'origine c'est un de toute façon) pour construire une structure de code hiérarchique. Quelque chose qui ressemblait à ceci:Ab-using languages ​​

CodeBuilder cb = new CodeBuilder(); 

using(cb.Function("foo")) 
{ 
    // Generate some function code 
    cb.Add(someStatement); 
    cb.Add(someOtherStatement); 

    using(cb.While(someCondition)) 
    { 
     cb.Add(someLoopStatement); 

     // Generate some more code 
    } 
} 

Il fonctionne parce que la fonction et les méthodes de retour Alors que l'objet IDisposable, que, sur Éliminez, dit le constructeur de fermer la portée actuelle. Une telle chose peut être utile pour toute structure arborescente qui doit être codée en dur.

Pensez-vous que de tels «hacks» sont justifiés? Parce que vous pouvez dire qu'en C++, par exemple, beaucoup de fonctionnalités telles que les templates et la surcharge des opérateurs sont surexploitées et ce comportement est encouragé par beaucoup (regardez boost par exemple). D'un autre côté, vous pouvez dire que de nombreuses langues modernes découragent de tels abus et vous donnent des caractéristiques spécifiques, beaucoup plus restreintes.

Mon exemple est, bien sûr, quelque peu ésotérique, mais réel. Alors que pensez-vous du piratage spécifique et de l'ensemble du problème? Avez-vous rencontré des dilemmes similaires? Combien d'abus pouvez-vous tolérer?

Répondre

3

Je pense que c'est quelque chose qui a soufflé sur des langues comme Ruby qui ont des mécanismes beaucoup plus étendus pour vous permettre de créer des langues dans votre langue (google pour "dsl" ou "domain specific languages" si vous voulez en savoir plus). C# est moins flexible à cet égard. Je pense que la création de DSL de cette manière est une bonne chose. Cela rend le code plus lisible. L'utilisation de blocs peut être une partie utile d'un DSL en C#. Dans ce cas, je pense qu'il existe de meilleures alternatives. L'utilisation de l'utilisation est ce cas un peu trop loin de son but initial. Cela peut perturber le lecteur. J'aime mieux la solution d'Anton Gogolev par exemple.

3

Offtopic, mais juste jeter un oeil à la façon dont joli cela devient avec lambdas:

var codeBuilder = new CodeBuilder(); 
codeBuilder.DefineFunction("Foo", x => 
{ 
    codeBuilder.While(condition, y => 
    { 
    } 
} 
+0

bien, je dois regarder plus dans C# 3.0 – Untrots

0

Je n'appellerais pas cela abus. Ressemble plus à une technique RAII imaginée pour moi. Les gens les utilisent pour des choses comme les moniteurs.

1

Si vous utilisez les définitions les plus strictes de IDisposable, il s'agit d'un abus. Il est destiné à être utilisé comme une méthode pour libérer des ressources natives de manière déterministe par un objet géré.

L'utilisation de IDisposable a évolué pour être essentiellement utilisée par "tout objet qui devrait avoir une durée de vie déterministe". Je ne dis pas que c'est écrit ou faux, mais c'est le nombre d'API et d'utilisateurs qui choisissent d'utiliser IDisposable. Compte tenu de cette définition, ce n'est pas un abus.

1

Je ne considérerais pas cela comme un mauvais abus, mais je ne le considérerais pas non plus comme une bonne forme à cause du mur cognitif que vous construisez pour vos développeurs d'entretien. L'instruction using implique une certaine classe de gestion de la durée de vie. C'est très bien dans ses usages habituels et dans ceux légèrement personnalisés (comme la référence de @ heeen à un analogue RAII), mais ces situations gardent toujours l'esprit de l'instruction using intacte.

Dans votre cas particulier, je pourrais faire valoir qu'une approche plus fonctionnelle comme @Anton Gogolev serait plus dans l'esprit de la langue et maintenable. En ce qui concerne votre question principale, je pense que chaque piratage doit être considéré comme la meilleure solution pour un langage particulier dans une situation particulière.La définition du meilleur est subjective, bien sûr, mais il y a certainement des moments (surtout quand les contraintes externes des budgets et des horaires sont jetés dans le mélange) où une approche légèrement plus hackish est la seule réponse raisonnable.

1

Je "abuse" souvent des blocs. Je pense qu'ils fournissent un excellent moyen de définir la portée. J'ai toute une série d'objets que j'utilise pour capturer et restaurer l'état (par exemple des zones de liste déroulante ou le pointeur de la souris) pendant les opérations qui peuvent changer l'état. Je les utilise également pour créer et supprimer des connexions de base de données.

.: par exemple

using(_cursorStack.ChangeCursor(System.Windows.Forms.Cursors.WaitCursor)) 
{ 
    ... 
} 
2

Il serait mieux si l'objet jetable retour de cb.Function (nom) a été l'objet sur lequel les déclarations doivent être ajoutées. Ce en interne ce générateur de fonction passé par les appels à des fonctions privées/internes sur le CodeBuilder est bien, juste que pour les consommateurs publics la séquence est claire.

Tant que l'implémentation Dispose rendrait le code suivant provoquant une erreur d'exécution.

CodeBuilder cb = new CodeBuilder(); 
var f = cb.Function("foo") 
using(function) 
{ 
    // Generate some function code 
    f.Add(someStatement); 
} 
function.Add(something); // this should throw 

Ensuite, le comportement est intuitive et relativement raisonnable et l'utilisation correcte (ci-dessous) encourage et empêche que cela se produise

CodeBuilder cb = new CodeBuilder(); 
using(var function = cb.Function("foo")) 
{ 
    // Generate some function code 
    function.Add(someStatement); 
} 

je dois vous demander pourquoi vous utilisez vos propres classes plutôt que les implémentations fournies CodeDomProvider bien que. (Il y a de bonnes raisons à cela, notamment que la mise en œuvre actuelle manque beaucoup de fonctionnalités C# 3.0) mais puisque vous ne le mentionnez pas vous-même ...

Editer: Je recommanderais Anoton d'utiliser lamdas. La lisibilité est beaucoup améliorée (et vous avez l'option de permettre Expression Trees

Questions connexes