Condividi tramite


Generazione di codice sorgente e compilazione di un programma a partire da un grafo CodeDOM

Nello spazio dei nomi System.CodeDom.Compiler vengono fornite interfacce per la generazione di codice sorgente da oggetti grafo CodeDOM e per la gestione della compilazione con i compilatori supportati. Un provider di codice è in grado di produrre codice sorgente in un determinato linguaggio di programmazione, in base a un grafo CodeDOM. Una classe derivata da CodeDomProvider può in genere fornire i metodi per la generazione e la compilazione di codice per il linguaggio supportato dal provider.

Utilizzo di un provider di codice CodeDOM per la generazione di codice sorgente

Per generare codice sorgente in un determinato linguaggio, è necessario un grafo CodeDOM che rappresenti la struttura del codice sorgente da generare.

Nell'esempio di codice riportato di seguito viene illustrato come creare un'istanza del controllo CSharpCodeProvider.

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

Il grafo per la generazione del codice è solitamente contenuto in una CodeCompileUnit. Per generare codice per una CodeCompileUnit contenente un grafo CodeDOM, chiamare il metodo GenerateCodeFromCompileUnit del provider di codice. Tale metodo accetta come parametro un TextWriter, utilizzato per generare il codice sorgente. In alcuni casi è pertanto necessario creare prima un TextWriter in cui sia possibile scrivere. Nell'esempio che segue viene illustrato come generare codice da una CodeCompileUnit e come scrivere il codice sorgente generato in un file denominato HelloWorld.cs.

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
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:
    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;
    }

Utilizzo di un provider di codice CodeDOM per la compilazione di assembly

Avvio della compilazione

Per compilare un assembly mediante un provider CodeCom, è necessario disporre di un compilatore e del codice sorgente scritto nel relativo linguaggio o di un grafo CodeDOM da cui generare il codice sorgente da compilare.

Se si desidera effettuare la compilazione a partire da un grafo CodeDOM, passare la CodeCompileUnit contenente il grafo al metodo CompileAssemblyFromDom del provider di codice. Se si dispone di un file di codice sorgente scritto in un linguaggio accettato dal compilatore, passare il nome del file al metodo CompileAssemblyFromFile del provider CodeDom. È anche possibile passare una stringa contenente codice sorgente scritto in un linguaggio accettato dal compilatore al metodo CompileAssemblyFromSource del provider CodeDom.

Configurazione dei parametri di compilazione

Tutti i metodi standard di avvio della compilazione di un provider CodeDom accettano parametri di tipo CompilerParameters per la specifica delle opzioni da utilizzare per la compilazione.

Per specificare un nome per il file di assembly ottenuto, utilizzare la proprietà OutputAssembly di CompilerParameters. In alternativa, al file di output verrà assegnato un nome predefinito.

Per impostazione predefinita, un nuovo CompilerParameters viene inizializzato con la relativa proprietà GenerateExecutable impostata su false. Se si compila un programma eseguibile, la proprietà GenerateExecutable deve essere impostata su true. Quando GenerateExecutable è impostata su false, il compilatore genererà una libreria di classi.

Se è in corso la compilazione di un eseguibile da un grafo CodeDOM, sarà necessario definire un CodeEntryPointMethod nel grafo. In presenza di più punti di ingresso al codice, può essere necessario impostare la proprietà MainClass di CompilerParameters sul nome della classe che definisce il punto di ingresso da utilizzare.

Per includere informazioni di debug nell'eseguibile generato, impostare la proprietà IncludeDebugInformation su true.

Se il progetto contiene riferimenti a uno o più assembly, è necessario specificare i nomi degli assembly come elementi di uno StringCollection nella proprietà ReferencedAssemblies del CompilerParameters utilizzato all'avvio della compilazione.

È possibile compilare un assembly scritto in memoria piuttosto che su disco impostando la proprietà GenerateInMemory su true. Quando un assembly viene generato in memoria, è possibile che il codice ottenga un riferimento all'assembly generato dalla proprietà CompiledAssembly di un CompilerResults. Se un assembly viene scritto su disco, sarà possibile ottenere il percorso dell'assembly generato tramite la proprietà PathToAssembly di un CompilerResults.

Per specificare una stringa personalizzata di argomenti della riga di comando da utilizzare quando si richiama il processo di compilazione, impostare la stringa nella proprietà CompilerOptions.

Se è necessario un token di sicurezza Win32 per richiamare il processo di compilazione, specificare il token nella proprietà UserToken.

Per collegare un file di risorse Win32 nell'assembly compilato, specificare il nome del file di risorse Win32 nella proprietà Win32Resource.

Per specificare un livello di avviso in corrispondenza del quale interrompere la compilazione, impostare la proprietà WarningLevel su un intero che rappresenta il livello di avviso in corrispondenza del quale interrompere la compilazione. Se vengono rilevati avvisi impostando la proprietà TreatWarningsAsErrors su true, sarà anche possibile configurare il compilatore per interrompere la compilazione.

Nell'esempio di codice riportato di seguito viene illustrato come compilare un file di codice sorgente utilizzando un provider CodeDom derivato dalla classe CodeDomProvider.

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
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:
    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;
        }
    }

Linguaggi supportati

Con .NET Framework vengono forniti compilatori e generatori di codice per i seguenti linguaggi: C#, Visual Basic, C++, J# e JScript. Il supporto CodeDOM può essere esteso ad altri linguaggi implementando generatori di codice e compilatori di codice specifici del linguaggio.

Vedere anche

Riferimenti

Riferimento rapido per CodeDOM

System.CodeDom

System.CodeDom.Compiler

Altre risorse

Generazione e compilazione dinamica di codice sorgente