Generar y compilar código fuente a partir de un gráfico CodeDOM

El espacio de nombres System.CodeDom.Compiler proporciona interfaces para generar código fuente a partir de gráficos de objetos CodeDOM y para administrar la compilación con compiladores compatibles. Un proveedor de código puede generar código fuente en un lenguaje de programación determinado según un gráfico CodeDOM. Una clase que deriva de CodeDomProvider normalmente puede proporcionar métodos para generar y compilar código para el lenguaje admitido por el proveedor.

Usar un proveedor de código CodeDOM para generar el código fuente

Para generar código fuente en un lenguaje determinado, se necesita un gráfico CodeDOM que represente la estructura del código fuente que se va a generar.

En el ejemplo siguiente se muestra cómo crear una instancia de CSharpCodeProvider:

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

El gráfico para la generación de código normalmente se encuentra en un elemento CodeCompileUnit. Para generar código para un elemento CodeCompileUnit que contiene un gráfico CodeDOM, llame al método GenerateCodeFromCompileUnit del proveedor de código. Este método tiene un parámetro para TextWriter que se usa para generar el código fuente, por lo que a veces es necesario crear primero un elemento TextWriter en el que se pueda escribir. En el ejemplo siguiente se muestra la generación de código a partir de un elemento CodeCompileUnit y la escritura del código fuente generado en un archivo denominado 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

Usar un proveedor de código CodeDOM para compilar ensamblados

Invocar compilación

Para compilar un ensamblado mediante un proveedor CodeDom, se debe tener código fuente para compilar en un lenguaje para el que se tenga un compilador, o bien se debe disponer de un gráfico CodeDOM a partir del que se pueda generar ese código fuente que se va a compilar.

Si está compilando a partir de un gráfico CodeDOM, pase el elemento CodeCompileUnit que contiene el gráfico al método CompileAssemblyFromDom del proveedor de código. Si tiene un archivo de código fuente en un lenguaje que el compilador entiende, pase el nombre del archivo que contiene el código fuente al método CompileAssemblyFromFile del proveedor CodeDom. También puede pasar una cadena que contiene el código fuente en un lenguaje que el compilador entiende al método CompileAssemblyFromSource del proveedor CodeDom.

Configurar parámetros de compilación

Todos los métodos de invocación de compilación estándar de un proveedor CodeDom tienen un parámetro de tipo CompilerParameters que indica las opciones que se van a usar para la compilación.

Puede especificar un nombre de archivo para el ensamblado de salida en la propiedad OutputAssembly de CompilerParameters. De lo contrario, se usará un nombre de archivo de salida predeterminado.

De forma predeterminada, se inicializa un nuevo CompilerParameters con su propiedad GenerateExecutable establecida en false. Si está compilando un programa ejecutable, debe establecer la propiedad GenerateExecutable en true. Cuando el GenerateExecutable se establece en false, el compilador generará una biblioteca de clases.

Si está compilando un ejecutable a partir de un gráfico CodeDOM, se debe definir un elemento CodeEntryPointMethod en el gráfico. Si hay varios puntos de entrada de código, puede ser necesario establecer la propiedad MainClass de CompilerParameters en el nombre de la clase que define el punto de entrada que se va a usar.

Para incluir información de depuración en un archivo ejecutable generado, establezca la propiedad IncludeDebugInformation en true.

Si el proyecto hace referencia a algún ensamblado, debe especificar los nombres de ensamblado como elementos de una StringCollection como la propiedad ReferencedAssemblies de CompilerParameters que usa al invocar la compilación.

Puede compilar un ensamblado que se escribe en memoria en lugar de en disco si establece la propiedad GenerateInMemory en true. Cuando se genera un ensamblado en memoria, el código puede obtener una referencia al ensamblado generado a partir de la propiedad CompiledAssembly de CompilerResults. Si un ensamblado se escribe en disco, puede obtener la ruta de acceso al ensamblado generado a partir de la propiedad PathToAssembly de CompilerResults.

Para especificar una cadena de argumentos de línea de comandos personalizada que se usará al invocar al proceso de compilación, establezca la cadena en la propiedad CompilerOptions.

Si se necesita un token de seguridad de Win32 para invocar al proceso de compilación, especifique el token en la propiedad UserToken.

Para vincular un archivo de recursos de Win32 al ensamblado compilado, especifique el nombre del archivo de recursos de Win32 en la propiedad Win32Resource.

Para especificar un nivel de advertencia en el que detener la compilación, establezca la propiedad WarningLevel en un entero que represente el nivel de advertencia en el que detener la compilación. También puede establecer la propiedad TreatWarningsAsErrors en true para que se detenga la compilación si se producen advertencias.

En el ejemplo de código siguiente se muestra cómo compilar un archivo de origen con un proveedor CodeDom derivado de la clase 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

Lenguajes con compatibilidad inicial

.NET proporciona compiladores y generadores de código para los siguientes lenguajes: C#, Visual Basic, C++ y JScript. La compatibilidad de CodeDOM se puede extender a otros lenguajes si se implementan generadores y compiladores de código específicos del lenguaje.

Vea también