Générer et compiler du code source à partir d’un graphe CodeDOM

L’espace de noms System.CodeDom.Compiler fournit des interfaces pour la génération de code source à partir de graphiques d’objets CodeDOM et pour la gestion de la compilation avec les compilateurs pris en charge. Un fournisseur de code peut produire du code source dans un langage de programmation particulier en fonction d’un graphique CodeDOM. Une classe qui dérive de CodeDomProvider peut fournir en général des méthodes pour générer et compiler le code pour le langage pris en charge par le fournisseur.

Utiliser un fournisseur de code CodeDOM pour générer du code source

Pour générer du code source dans un langage particulier, vous avez besoin d’un graphique CodeDOM qui représente la structure du code source à générer.

L’exemple suivant montre comment créer une instance de CSharpCodeProvider :

CSharpCodeProvider^ provider = gcnew CSharpCodeProvider();
CSharpCodeProvider provider = new CSharpCodeProvider();
Dim provider As New CSharpCodeProvider()

Le graphique de génération du code est généralement contenu dans un CodeCompileUnit. Pour générer du code pour un CodeCompileUnit qui contient un graphe CodeDOM, appelez la méthode GenerateCodeFromCompileUnit du fournisseur de code. Cette méthode a un paramètre pour un TextWriter qu’elle utilise pour générer le code source. Ainsi, il est parfois nécessaire de créer d’abord un TextWriter accessible en écriture. L’exemple suivant illustre la génération de code à partir d’un CodeCompileUnit et l’écriture du code source généré dans un fichier nommé HelloWorld.cs.

public:
    static String^ GenerateCSharpCode(CodeCompileUnit^ compileunit)
    {
        // Generate the code with the C# code provider.
        CSharpCodeProvider^ provider = gcnew CSharpCodeProvider();

        // Build the output file name.
        String^ sourceFile;
        if (provider->FileExtension[0] == '.')
        {
           sourceFile = "HelloWorld" + provider->FileExtension;
        }
        else
        {
           sourceFile = "HelloWorld." + provider->FileExtension;
        }

        // Create a TextWriter to a StreamWriter to the output file.
        StreamWriter^ sw = gcnew StreamWriter(sourceFile, false);
        IndentedTextWriter^ tw = gcnew IndentedTextWriter(sw, "    ");

            // Generate source code using namespace the code provider.
        provider->GenerateCodeFromCompileUnit(compileunit, tw,
            gcnew CodeGeneratorOptions());

        // Close the output file.
        tw->Close();
        sw->Close();

        return sourceFile;
    }
public static string GenerateCSharpCode(CodeCompileUnit compileunit)
{
    // Generate the code with the C# code provider.
    CSharpCodeProvider provider = new CSharpCodeProvider();

    // Build the output file name.
    string sourceFile;
    if (provider.FileExtension[0] == '.')
    {
       sourceFile = "HelloWorld" + provider.FileExtension;
    }
    else
    {
       sourceFile = "HelloWorld." + provider.FileExtension;
    }

    // Create a TextWriter to a StreamWriter to the output file.
    using (StreamWriter sw = new StreamWriter(sourceFile, false))
    {
        IndentedTextWriter tw = new IndentedTextWriter(sw, "    ");

        // Generate source code using the code provider.
        provider.GenerateCodeFromCompileUnit(compileunit, tw,
            new CodeGeneratorOptions());

        // Close the output file.
        tw.Close();
    }

    return sourceFile;
}
Public Shared Function GenerateCSharpCode(compileunit As CodeCompileUnit) As String
    ' Generate the code with the C# code provider.
    Dim provider As New CSharpCodeProvider()

    ' Build the output file name.
    Dim sourceFile As String
    If provider.FileExtension(0) = "." Then
        sourceFile = "HelloWorld" + provider.FileExtension
    Else
        sourceFile = "HelloWorld." + provider.FileExtension
    End If

    ' Create a TextWriter to a StreamWriter to the output file.
    Using sw As New StreamWriter(sourceFile, false)
        Dim tw As New IndentedTextWriter(sw, "    ")

        ' Generate source code Imports the code provider.
        provider.GenerateCodeFromCompileUnit(compileunit, tw, _
            New CodeGeneratorOptions())

        ' Close the output file.
        tw.Close()
    End Using

    Return sourceFile
End Function

Utiliser un fournisseur de code CodeDOM pour compiler des assemblys

Appeler la compilation

Pour compiler un assembly à l’aide d’un fournisseur CodeDom, vous devez disposer du code source à compiler dans un langage pour lequel vous avez un compilateur, ou d’un graphique CodeDOM à partir duquel ce code source à compiler peut être généré.

Si vous compilez un graphique CodeDOM, passez le CodeCompileUnit contenant le graphique à la méthode CompileAssemblyFromDom du fournisseur de code. Si vous avez un fichier de code source dans un langage que le compilateur comprend, passez le nom du fichier contenant le code source à la méthode CompileAssemblyFromFile du fournisseur CodeDom. Vous pouvez aussi passer une chaîne contenant le code source dans un langage que le compilateur comprend à la méthode CompileAssemblyFromSource du fournisseur CodeDom.

Configurer les paramètres de compilation

Toutes les méthodes d’appel de compilation standard d’un fournisseur CodeDom ont un paramètre de type CompilerParameters qui indique les options à utiliser pour la compilation.

Vous pouvez spécifier un nom de fichier pour l’assembly de sortie dans la propriété OutputAssembly de CompilerParameters. Sinon, un nom de fichier de sortie par défaut est utilisé.

Par défaut, un nouveau CompilerParameters est initialisé avec sa propriété GenerateExecutable définie sur false. Si vous compilez un programme exécutable, vous devez définir la propriété GenerateExecutable sur true. Quand GenerateExecutable est défini sur false, le compilateur génère une bibliothèque de classes.

Si vous compilez un exécutable à partir d’un graphique CodeDOM, un CodeEntryPointMethod doit être défini dans le graphique. S’il existe plusieurs points d’entrée de code, il peut être nécessaire d’affecter à la propriété MainClass de CompilerParameters le nom de la classe qui définit le point d’entrée à utiliser.

Pour inclure des informations de débogage dans un exécutable généré, définissez la propriété IncludeDebugInformation sur true.

Si votre projet référence des assemblys, vous devez spécifier les noms des assemblys en tant qu’éléments dans un StringCollection en tant que propriété ReferencedAssemblies du CompilerParameters que vous utilisez pour appeler la compilation.

Vous pouvez compiler un assembly écrit en mémoire plutôt que sur disque en définissant la propriété GenerateInMemory sur true. Quand un assembly est généré en mémoire, votre code peut obtenir une référence à l’assembly généré à partir de la propriétés CompiledAssembly d’un CompilerResults. Si un assembly est écrit sur disque, vous pouvez obtenir le chemin de l’assembly généré à partir de la propriété PathToAssembly d’un CompilerResults.

Pour spécifier une chaîne d’arguments de ligne de commande personnalisée à utiliser lors de l’appel du processus de compilation, définissez la chaîne dans la propriété CompilerOptions.

Si un jeton de sécurité Win32 est nécessaire pour appeler le processus de compilation, spécifiez-le dans la propriété UserToken.

Pour lier un fichier de ressources Win32 dans l’assembly compilé, spécifiez le nom du fichier de ressources Win32 dans la propriété Win32Resource.

Pour spécifier un niveau d’avertissement auquel il faut arrêter la compilation, affectez à la propriété WarningLevel un entier qui représente le niveau d’avertissement. Vous pouvez également configurer le compilateur pour arrêter la compilation si des avertissements sont générés en définissant la propriété TreatWarningsAsErrors sur true.

L’exemple de code suivant illustre la compilation d’un fichier source à l’aide d’un fournisseur CodeDom dérivé de la classe CodeDomProvider.

public:
    static bool CompileCSharpCode(String^ sourceFile, String^ exeFile)
    {
        CSharpCodeProvider^ provider = gcnew CSharpCodeProvider();

        // Build the parameters for source compilation.
        CompilerParameters^ cp = gcnew CompilerParameters();

        // Add an assembly reference.
        cp->ReferencedAssemblies->Add( "System.dll" );

        // Generate an executable instead of
        // a class library.
        cp->GenerateExecutable = true;

        // Set the assembly file name to generate.
        cp->OutputAssembly = exeFile;

        // Save the assembly as a physical file.
        cp->GenerateInMemory = false;

        // Invoke compilation.
        CompilerResults^ cr = provider->CompileAssemblyFromFile(cp, sourceFile);

       if (cr->Errors->Count > 0)
       {
           // Display compilation errors.
            Console::WriteLine("Errors building {0} into {1}",
                sourceFile, cr->PathToAssembly);
            for each (CompilerError^ ce in cr->Errors)
            {
                Console::WriteLine("  {0}", ce->ToString());
                Console::WriteLine();
            }
        }
        else
        {
            Console::WriteLine("Source {0} built into {1} successfully.",
                sourceFile, cr->PathToAssembly);
        }

        // Return the results of compilation.
        if (cr->Errors->Count > 0)
        {
            return false;
        }
        else
        {
            return true;
        }
    }
public static bool CompileCSharpCode(string sourceFile, string exeFile)
{
    CSharpCodeProvider provider = new CSharpCodeProvider();

    // Build the parameters for source compilation.
    CompilerParameters cp = new CompilerParameters();

    // Add an assembly reference.
    cp.ReferencedAssemblies.Add( "System.dll" );

    // Generate an executable instead of
    // a class library.
    cp.GenerateExecutable = true;

    // Set the assembly file name to generate.
    cp.OutputAssembly = exeFile;

    // Save the assembly as a physical file.
    cp.GenerateInMemory = false;

    // Invoke compilation.
    CompilerResults cr = provider.CompileAssemblyFromFile(cp, sourceFile);

   if (cr.Errors.Count > 0)
   {
       // Display compilation errors.
        Console.WriteLine("Errors building {0} into {1}",
            sourceFile, cr.PathToAssembly);
        foreach (CompilerError ce in cr.Errors)
        {
            Console.WriteLine("  {0}", ce.ToString());
            Console.WriteLine();
        }
    }
    else
    {
        Console.WriteLine("Source {0} built into {1} successfully.",
            sourceFile, cr.PathToAssembly);
    }

    // Return the results of compilation.
    if (cr.Errors.Count > 0)
    {
        return false;
    }
    else
    {
        return true;
    }
}
Public Shared Function CompileCSharpCode(sourceFile As String, _
    exeFile As String) As Boolean
    Dim provider As New CSharpCodeProvider()

    ' Build the parameters for source compilation.
    Dim cp As New CompilerParameters()

    ' Add an assembly reference.
    cp.ReferencedAssemblies.Add("System.dll")

    ' Generate an executable instead of
    ' a class library.
    cp.GenerateExecutable = true

    ' Set the assembly file name to generate.
    cp.OutputAssembly = exeFile

    ' Save the assembly as a physical file.
    cp.GenerateInMemory = false

    ' Invoke compilation.
    Dim cr As CompilerResults = provider.CompileAssemblyFromFile(cp, sourceFile)

    If cr.Errors.Count > 0 Then
        ' Display compilation errors.
        Console.WriteLine("Errors building {0} into {1}", _
            sourceFile, cr.PathToAssembly)
        For Each ce As CompilerError In cr.Errors
            Console.WriteLine("  {0}", ce.ToString())
            Console.WriteLine()
        Next ce
    Else
        Console.WriteLine("Source {0} built into {1} successfully.", _
            sourceFile, cr.PathToAssembly)
    End If

    ' Return the results of compilation.
    If cr.Errors.Count > 0 Then
        Return False
    Else
        Return True
    End If
End Function

Langages avec prise en charge initiale

.NET fournit des compilateurs de code et des générateurs de code pour les langages suivants : C#, Visual Basic, C++ et JScript. La prise en charge de codeDOM peut être étendue à d’autres langages en implémentant des générateurs de code et des compilateurs de code propres au langage.

Voir aussi