2 votes

Méthode propre, efficace et infaillible de génération programmatique de fichiers de code C#

Je voudrais savoir s'il existe un bon moyen de produire du code C# de manière programmatique sans manipuler des chaînes de caractères ou des StringBuilders. De plus, il faudrait vérifier si le code se compile, mais je suppose que cela peut être fait en utilisant CSharpCodeProvider.

Je cherche quelque chose comme ce qui suit :

CodeUnit unit = new CodeUnit();
unit.AddDefaultUsings();
unit.AddUsing("MyApi.CoolNameSpace", "MyApi.Yay");
var clazz = unit.AddClass("GeneratedClass", Access.Public);
clazz.AddConstructor("....");
if(unit.Compile() != true)
    //oh dang, somethings wrong!
else unit.WriteUTF8To("GeneratedClass.cs");

Cela pourrait faire partie de la bibliothèque de base (je ne pense pas que CSharpCodeProvider puisse faire cela ?) ou d'une bibliothèque externe, mais ce n'est pas du tout mon fort (produire dynamiquement du code en utilisant c#), donc si cela semble être une erreur, c'est parce que je le suis !

5voto

svick Points 81772

C'est exactement la raison d'être de CodeDOM :

var unit = new CodeCompileUnit();

var @namespace = new CodeNamespace("GeneratedCode");
unit.Namespaces.Add(@namespace);

// AddDefault() doesn't exist, but you can create it as an extension method
@namespace.Imports.AddDefault();
@namespace.Imports.Add(new CodeNamespaceImport("MyApi.CoolNameSpace"));

var @class = new CodeTypeDeclaration("GeneratedClass");
@namespace.Types.Add(@class);

@class.TypeAttributes = TypeAttributes.Class | TypeAttributes.Public;

var constructor = new CodeConstructor();
constructor.Attributes = MemberAttributes.Public;
constructor.Parameters.Add(
    new CodeParameterDeclarationExpression(typeof(string), "name"));

constructor.Statements.Add(…);

@class.Members.Add(constructor);

var provider = new CSharpCodeProvider();

var result = provider.CompileAssemblyFromDom(new CompilerParameters(), unit);

Bien qu'il puisse être assez verbeux. De plus, elle essaie d'être indépendante du langage, ce qui signifie que vous ne pouvez pas utiliser les fonctionnalités spécifiques à C# comme les classes statiques, les méthodes d'extension, les expressions de requête LINQ ou les lambdas en utilisant cette API. Ce que vous pouvez faire cependant, c'est placer n'importe quelle chaîne dans le corps de la méthode. Ainsi, vous pouvez utiliser certaines fonctionnalités spécifiques à C#, mais uniquement en manipulant des chaînes de caractères, ce que vous essayiez d'éviter.

0voto

armandomiani Points 521

J'aime utiliser le Moteur de modèles NVelocity .

0voto

Archie Points 56

Vous pouvez utiliser les classes Reflection.Emit comme MethodBuilder . Les arbres d'expression les accompagnent également. C'est plutôt CLS que C#.

0voto

jgauffin Points 51913

J'ai fait une enveloppe autour de codedom. Il vous suffit de créer votre propre script en C# et de spécifier les types utilisés. Les espaces de noms et les assemblages seront automatiquement inclus.

Exemple

public interface IWorld
{
    string Hello(string value);
}

string code = @"namespace MyNamespace
{
  class Temp : IWorld
  {
      public string Hello(string value)
      {
          return ""World "" + value;
      }
  }
}";

Compiler compiler = new Compiler();
compiler.AddType(typeof(string));
compiler.Compile(code);
var obj = compiler.CreateInstance<IWorld>();
string result = obj.Hello("World!");

Notez que je l'ai écrit il y a longtemps. L'exemple peut ne pas fonctionner à 100%. (La classe du compilateur fonctionne, l'exemple peut l'utiliser de manière incorrecte).

Code source :

http://fadd.codeplex.com/SourceControl/changeset/view/67972#925984

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