Question

Je l'ai entendu des gens affirment que le Code générateurs et modèles T4 ne doivent pas être utilisés. La logique derrière cela est que si vous générez code avec un générateur alors il y a une meilleure façon plus efficace pour construire le code par les génériques et templating.

Alors que je suis d'accord avec cette affirmation un peu plus haut, je ne l'ai pas vraiment trouvé des moyens efficaces pour construire des modèles qui peuvent dire, par exemple, s'instancier. En d'autres termes, je ne peux jamais faire:

return new T();

De plus, si je veux générer un code basé sur des valeurs de base de données que j'ai trouvé que l'utilisation Microsoft.SqlServer.Management.SMO conjointement avec des modèles T4 ont été merveilleux à générer des quantités de masse de code sans avoir à copier / coller ou utiliser ReSharper.

Bon nombre des problèmes que j'ai trouvé avec Generics aussi que mon choc, il y a beaucoup de développeurs qui ne les comprennent pas. Quand j'examine les médicaments génériques pour une solution, il y a des moments où ça se complique parce que C # indique que vous ne pouvez pas faire quelque chose qui peut sembler logique dans mon esprit.

Que pensez-vous? Préférez-vous construire un générateur, ou préférez-vous utiliser les médicaments génériques? Par ailleurs, comment bien génériques aller? Je sais une bonne quantité sur les médicaments génériques, mais il y a des pièges et des pièges que je rencontre toujours dans cette cause me de recourir à un modèle T4.

Quelle est la façon de gérer des scénarios plus approprié où vous avez besoin d'une grande quantité de flexibilité? Oh, et comme un bonus à cette question, ce sont de bonnes ressources sur C # et Generics?

Était-ce utile?

La solution

Vous pouvez faire de nouveaux T (); si vous faites cela

public class Meh<T>
  where T : new()
{
  public static T CreateOne()
  {
    return new T();
  }
}

En ce qui concerne le code-générateurs. J'utilise un tous les jours sans aucun problème. J'utilise un moment en fait: -)

Génériques résoudre un problème, le code-générateurs à résoudre un autre. Par exemple, la création d'un modèle d'entreprise à l'aide d'un éditeur UML, puis générer vos classes avec le code de persistance comme je le fais tout le temps en utilisant ce outil n'a pas pu être atteint avec les génériques, parce que chaque classe persistante est complètement différent.

En ce qui concerne une bonne source sur les médicaments génériques. Le meilleur a obtenu d'être livre de Jon Skeet bien sûr! : -)

Autres conseils

En tant qu'initiateur de T4, j'ai dû défendre cette question assez peu de fois que vous pouvez imaginer: -)

Ma conviction est que, à sa meilleure génération de code est une étape sur la façon de produire de la valeur équivalente en utilisant des bibliothèques réutilisables.

Comme beaucoup d'autres l'ont dit, le concept clé pour maintenir DRY est jamais, en changeant le code généré toujours manuellement, mais plutôt la préservation de votre capacité à se régénérer lorsque les changements de métadonnées source ou vous trouvez un bogue dans le générateur de code. A ce moment-là le code généré a beaucoup des caractéristiques du code objet et vous ne courez pas de problèmes de type copier / coller.

En général, il y a beaucoup moins d'effort pour produire un générateur de code paramétrés (en particulier avec les systèmes basés sur des modèles) que de concevoir correctement une bibliothèque de base de haute qualité qui obtient le coût d'utilisation vers le bas au même niveau, il est donc un rapide façon d'obtenir la valeur de la cohérence et de supprimer les erreurs de répétition.

Cependant, je crois toujours que serait le plus souvent d'améliorer le système fini en ayant moins de code au total. Si rien d'autre, son empreinte mémoire serait presque toujours beaucoup plus petit (bien que les gens ont tendance à penser des médicaments génériques que le coût libre à cet égard, qui certainement, ils ne sont pas).

Si vous avez réalisé une valeur à l'aide d'un générateur de code, cela vous achète souvent un peu de temps ou d'argent ou de bonne volonté d'investir dans la récolte d'une bibliothèque de la base de code généré. Vous pouvez ensuite reconcevoir progressivement le générateur de code pour cibler la nouvelle bibliothèque et générer, espérons beaucoup moins de code. Rincer et répéter.

Un contrepoint intéressant qui a été fait pour moi et qui vient dans ce fil est que ne sont pas la chose la plus facile riches, complexes, bibliothèques paramétriques en termes de courbe d'apprentissage, en particulier pour ceux qui ne profondément immergé dans la plate-forme. Coller avec la génération de code sur les cadres de base plus simple peut produire un code bavard, mais il peut souvent être assez simple et facile à lire.

Bien sûr, vous avez beaucoup de variance et le paramétrage extrêmement riche en votre générateur, vous pourriez être troquer la complexité de votre produit un de la complexité dans vos modèles. Ceci est un chemin facile à glisser dans et peut faire l'entretien tout autant d'un mal de tête -. Attention pour que

Code Génération est pas mal et il n'a pas d'odeur! La clé est de générer le code au bon moment. Je pense que T4 est grand - je ne l'utilise que de temps en temps, mais quand je le fais est très utile. Dire, sans condition, ce code de génération est mauvais est inconditionnellement fou!

Il me semble générateurs de code sont bien aussi longtemps que la génération de code fait partie de votre processus de construction normale, plutôt que quelque chose que vous exécutez une fois, puis garder sa sortie. J'ajoute cette mise en garde, car s'il suffit d'utiliser le générateur de code une fois et jeter les données qui l'a créé, vous êtes juste créer automatiquement une violation massive et des maux de tête SEC entretien; alors que la génération du code à chaque fois que signifie effectivement que ce que vous utilisez pour faire la production est le véritable code source et les fichiers générés ne sont que les étapes intermédiaires de compilation que vous devriez surtout ignorer.

Lex et Yacc sont des exemples classiques d'outils de vous permettent de spécifier la fonctionnalité d'une manière efficace et générer du code efficace de celui-ci. Essayer de faire leur travail à la main va allonger votre temps de développement et probablement produire un code moins efficace et moins lisible. Et pendant que vous pourriez certainement intégrer quelque chose comme lex et yacc directement dans votre code et faire leur travail au moment de l'exécution au lieu de la compilation, ce serait certainement considérablement la complexité de votre code et ralentir. Si vous avez réellement besoin de changer vos spécifications au moment de l'exécution, il pourrait valoir la peine, mais dans la plupart des cas normaux en utilisant lex / yacc à code pour vous générer au moment de la compilation est une grande victoire.

Un bon pourcentage de ce qui est dans Visual Studio 2010 ne serait pas possible sans génération de code. Entity Framework ne serait pas possible. Le simple fait de glisser-déposer un contrôle sur une forme ne serait pas possible, pas plus que Linq. Dire que la génération de code ne doit pas être utilisé est étrange que tant l'utiliser sans même y penser.

Peut-être qu'il est un peu dur, mais pour moi sent la génération de code.

Cette génération de code est utilisé signifie qu'il existe de nombreux principes communs sous-jacents qui peuvent être exprimées dans un « Ne pas vous répéter » la mode. Il peut prendre un peu plus longtemps, mais il est satisfaisant quand vous vous retrouvez avec des classes qui ne contiennent que les bits qui changent vraiment, à partir d'une infrastructure qui contient la mécanique.

Quant à Generics ... non, je n'ai pas trop de problèmes avec elle. La seule chose qui ne fonctionne pas actuellement dit que

List<Animal> a = new List<Animal>();
List<object> o = a;

Mais même cela sera possible dans la prochaine version de C #.

Code signifie plus de complexité Plus. Plus la complexité signifie plus d'endroits pour se cacher des bugs, ce qui signifie des cycles plus longs, fixes ce qui signifie des coûts plus élevés tout au long du projet.

Chaque fois que possible, je préfère minimiser la quantité de code pour fournir des fonctionnalités équivalentes; de préférence en utilisant des approches dynamiques (programmes) plutôt que la génération de code. La réflexion, les attributs, les aspects et les génériques offrent beaucoup d'options pour une stratégie SEC, laissant génération en dernier recours.

La génération de code est pour moi une solution pour de nombreux problèmes rencontrés dans le langage, les cadres, etc. Ils ne sont pas mauvais par eux-mêmes, je dirais qu'il est très très mauvais (à savoir le mal) pour libérer une langue (C #) et d'un cadre qui vous oblige à copier-coller (échange sur les propriétés, les événements de déclenchement, le manque de macros) ou utiliser des nombres magiques (WPF de liaison).

Alors, je pleure, mais je les utiliser, parce que je dois.

Je l'ai utilisé T4 pour la génération de code et aussi Generics. Les deux sont bons, ont leurs avantages et leurs inconvénients, et sont adaptés à des fins différentes.

Dans mon cas, j'utilise T4 pour générer des entités, DAL et BLL basé sur un schéma de base de données. Cependant, DAL et BLL référence à un mini-ORM I construit, basé sur Generics et la réflexion. Donc, je pense que vous pouvez les utiliser côte à côte, aussi longtemps que vous gardez le contrôle et le garder petit et simple.

T4 génère un code statique, tandis que Generics est dynamique. Si vous utilisez Generics, vous utilisez la réflexion qui est dit moins que la solution performante « codée en dur ». Bien sûr, vous pouvez mettre en cache les résultats de la réflexion.

En ce qui concerne "return new T ();", j'utiliser des méthodes dynamiques comme ceci:

public class ObjectCreateMethod
    {
    delegate object MethodInvoker();
    MethodInvoker methodHandler = null;

    public ObjectCreateMethod(Type type)
    {
        CreateMethod(type.GetConstructor(Type.EmptyTypes));
    }

    public ObjectCreateMethod(ConstructorInfo target)
    {
        CreateMethod(target);
    }

    void CreateMethod(ConstructorInfo target)
    {
        DynamicMethod dynamic = new DynamicMethod(string.Empty,
                    typeof(object),
                    new Type[0],
                    target.DeclaringType);
        ILGenerator il = dynamic.GetILGenerator();
        il.DeclareLocal(target.DeclaringType);
        il.Emit(OpCodes.Newobj, target);
        il.Emit(OpCodes.Stloc_0);
        il.Emit(OpCodes.Ldloc_0);
        il.Emit(OpCodes.Ret);

        methodHandler = (MethodInvoker)dynamic.CreateDelegate(typeof(MethodInvoker));
    }

    public object CreateInstance()
    {
        return methodHandler();
    }
}

Alors, je l'appelle comme ceci:

ObjectCreateMethod _MetodoDinamico = new ObjectCreateMethod(info.PropertyType);
object _nuevaEntidad = _MetodoDinamico.CreateInstance();

Génériques et la génération de code sont deux choses différentes. Dans certains cas, vous pouvez utiliser les médicaments génériques au lieu de génération de code et pour ceux que je crois que vous devriez. Pour l'autre génération de code de cas est un outil puissant.

Pour tous les cas où vous avez besoin simplement de générer du code basé sur une entrée de données, la génération de code est le chemin à parcourir. La plus évidente, mais en aucun cas le seul exemple est l'éditeur de formulaires dans Visual Studio. Ici, l'entrée est les données de concepteur et la sortie est le code. Dans ce cas de médicaments génériques est vraiment aucune aide, mais il est très bien que VS génère simplement le code basé sur la mise en page de l'interface graphique.

Les générateurs de code peuvent être considérés comme une odeur de code qui indique un défaut ou d'un manque de fonctionnalité dans le langauge cible.

Par exemple, alors qu'il a été dit ici que « les objets qui persistent ne peut pas être généralisée », il serait préférable de penser comme des « objets en C # qui persistent automatiquement leurs données ne peuvent pas être généralisés en C # », parce que Je peux sûrement en Python grâce à l'utilisation de différentes méthodes.

L'approche Python pourrait cependant être imitée dans les langues statiques grâce à l'utilisation de l'opérateur [] (method_name sous forme de chaîne), qui renvoie soit un foncteur ou une chaîne, en fonction des besoins. Malheureusement, cette solution n'est pas toujours applicable, et le retour d'un foncteur peut être gênant.

Le point que je fais est que des générateurs de code indiquent un défaut dans une langue choisie qui sont réduites en fournissant une plus pratique spécialisée syntaxe pour le problème spécifique à portée de main.

Le type de code généré copier / coller (comme ORM faire) peut aussi être très utile ...

Vous pouvez créer votre base de données, puis ayant la ORM générer une copie de cette définition de base de données exprimées dans votre langue préférée.

L'avantage vient quand vous changez votre définition originale (la base de données), la compilation de la presse et l'ORM (si vous avez un bon) peut re-génère votre copie de la définition. Maintenant, toutes les références à la base de données peuvent être vérifiées par le type compilateurs vérificateur et votre code ne parviendra pas à compilent lorsque vous utilisez des tables ou des colonnes qui n'existent plus.

Réfléchissez à ceci: Si j'appelle une méthode plusieurs fois dans mon code, que je ne parle pas au nom que j'ai donné à cette méthode à l'origine? Je ne cesse de répéter ce nom encore et ... Les concepteurs de langue ont reconnu ce problème et est venu avec « Type-sécurité » comme la solution. Ne pas retirer les copies (comme DRY suggère que nous devrions faire), mais les vérifier pour l'exactitude à la place.

Le code généré ORM apporte la même solution en se référant aux noms de table et de colonne. Ne pas supprimer les copies / références, mais qui porte la définition de base de données dans votre (type-safe) langue où vous pouvez vous référer à des classes et des propriétés à la place. En collaboration avec les compilateurs vérification de type, cela résout un problème similaire d'une manière similaire: erreurs de compilation garantie au lieu de ceux d'exécution lorsque vous faites référence à des tables obsolètes ou mal orthographiés (classes) ou colonnes (propriétés)

.
citation

: Je ne l'ai pas vraiment trouvé des moyens efficaces pour construire des modèles qui peuvent dire, par exemple, s'instancier. En d'autres termes, je ne peux jamais faire:

return new T ();

public abstract class MehBase<TSelf, TParam1, TParam2>
    where TSelf : MehBase<TSelf, TParam1, TParam2>, new()
{
    public static TSelf CreateOne()
    {
        return new TSelf();
    }
}

public class Meh<TParam1, TParam2> : MehBase<Meh<TParam1, TParam2>, TParam1, TParam2>
{
    public void Proof()
    {
        Meh<TParam1, TParam2> instanceOfSelf1 = Meh<TParam1, TParam2>.CreateOne();
        Meh<int, string> instanceOfSelf2 = Meh<int, string>.CreateOne();
    }
} 

La génération de code, comme les génériques, les modèles, et d'autres raccourcis, est un outil puissant. Et comme avec la plupart des outils puissants, il amplifie le capaility de son utilisateur pour le bien et pour le mal -. Ils ne peuvent pas être séparés

Donc, si vous comprenez votre générateur de code à fond, tout anticiper produira, et pourquoi, et ont l'intention de le faire pour des raisons valables, alors à elle. Mais ne pas l'utiliser (ou l'une de l'autre technique) pour que vous avez passé un endroit où vous n'êtes pas sûr où vous vous dirigez vers, ou comment y arriver.

Certaines personnes pensent que, si vous obtenez votre problème actuel résolu et un comportement mis en œuvre, vous êtes en or. Il est pas toujours évident combien cochonneries et vous laisser dans l'opacité de votre chemin pour le prochain développeur (qui pourrait être vous-même.)

Pourquoi le fait d'être en mesure de copier / coller vraiment, vraiment rapide, le rendre plus acceptable?

C'est la seule justification de la génération de code que je peux voir.

Même si le générateur fournit toute la flexibilité dont vous avez besoin, vous avez encore à apprendre à utiliser cette flexibilité -. Qui est encore une autre couche d'apprentissage et de test nécessaire

Et même si elle fonctionne en temps zéro, il gonflerait encore le code.

Je roulais ma propre classe d'accès aux données. Il sait tout sur les connexions, les transactions, parms de procédures stockées, etc, etc, et je n'avais d'écrire tous les trucs de ADO.NET fois.

Il y a maintenant si longtemps que je devais écrire (ou même regarder) quoi que ce soit avec un objet de connexion, que je serais mal à se souvenir de la syntaxe désinvolture.

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