Generar código fuente y compilar un programa a partir de un gráfico CodeDOM
Actualización: noviembre 2007
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 admitidos. Un proveedor de código puede generar código fuente en un lenguaje de programación determinado de acuerdo con un gráfico CodeDOM. Por lo general, una clase derivada de CodeDomProvider 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 código fuente
Para generar código fuente en un lenguaje determinado, es necesario 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.
Dim provider As New CSharpCodeProvider()
CSharpCodeProvider provider = new CSharpCodeProvider();
Por lo general, el gráfico para la compilación de código se encuentra en CodeCompileUnit. Para generar código para una unidad CodeCompileUnit que contenga un gráfico CodeDOM, llame al método GenerateCodeFromCompileUnit del proveedor de código. Este método contiene un parámetro para un TextWriter que utiliza para generar el código fuente, por lo que a veces es necesario crear primero un TextWriter en el que se pueda escribir. En el siguiente ejemplo se muestra la forma de generar código a partir de una unidad CodeCompileUnit y la forma de escribir el código generado en un archivo denominado HelloWorld.cs.
Public Shared Function GenerateCSharpCode( _
compileunit As CodeCompileUnit) As String
' Generate the code with the C# code provider.
Dim provider As CSharpCodeProvider = New CSharpCodeProvider()
' Build the output file name.
Dim sourceFile As String
If provider.FileExtension.StartsWith(".")
sourceFile = "HelloWorld" + provider.FileExtension
Else
sourceFile = "HelloWorld." + provider.FileExtension
End If
' Create a TextWriter to a StreamWriter to an output file.
Dim tw As New IndentedTextWriter( _
New StreamWriter(sourceFile, False), " ")
' Generate source code using the code provider.
provider.GenerateCodeFromCompileUnit(compileunit, tw, _
New CodeGeneratorOptions())
' Close the output file.
tw.Close()
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.
IndentedTextWriter tw = new IndentedTextWriter(
new StreamWriter(sourceFile, false), " ");
// Generate source code using the code provider.
provider.GenerateCodeFromCompileUnit(compileunit, tw,
new CodeGeneratorOptions());
// Close the output file.
tw.Close();
return sourceFile;
}
Usar un proveedor de código CodeDOM para compilar ensamblados
Invocar la compilación
Para compilar un ensamblado mediante un proveedor CodeDom, es necesario disponer de código fuente para compilar en un lenguaje para el que se disponga de un compilador o bien disponer de un gráfico CodeDOM a partir del cual se pueda generar el código fuente que se va a compilar.
Si se está compilando a partir de un gráfico CodeDOM, pase la unidad CodeCompileUnit que contiene el gráfico al método CompileAssemblyFromDom del proveedor de código. Si dispone de un archivo de código fuente escrito en un lenguaje que el compilador puede entender, 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 contenga el código fuente escrito en un lenguaje que el compilador entienda 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 disponen de un parámetro del tipo CompilerParameters que indica las opciones que se van a utilizar 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 utilizará un nombre de archivo de salida predeterminado.
De forma predeterminada, se inicializa un nuevo parámetro CompilerParameters con la propiedad GenerateExecutable establecida en false. Si está compilando un programa ejecutable, debe establecer la propiedad GenerateExecutable en true. Si la propiedad GenerateExecutable se establece en false, el compilador generará una biblioteca de clases.
Si compila un ejecutable a partir de un gráfico CodeDOM, debe definir CodeEntryPointMethod en el gráfico. Si existen 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 utilizar.
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 ensamblados como elementos de una colección StringCollection como propiedad ReferencedAssemblies de los CompilerParameters utilizados al invocar la compilación.
Se puede compilar un ensamblado escrito en la memoria en lugar de en disco estableciendo la propiedad GenerateInMemory en true. Si se genera un ensamblado en memoria, el código puede obtener una referencia al ensamblado generado desde la propiedad CompiledAssembly de una clase 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 personalizada de argumentos de línea de comandos que se utilizarán al invocar el proceso de compilación, establezca la cadena en la propiedad CompilerOptions.
Si se requiere 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 se detendrá la compilación, establezca la propiedad WarningLevel en un entero que represente el nivel de advertencia en el que se detendrá la compilación. También se puede configurar el compilador para que detenga la compilación si se producen advertencias; para ello, establezca la propiedad TreatWarningsAsErrors en true.
En el siguiente ejemplo de código se muestra la forma de compilar un archivo de código fuente utilizando un proveedor CodeDom derivado de la clase CodeDomProvider.
Public Shared Function CompileCSharpCode(sourceFile As String, _
exeFile As String) As Boolean
Dim provider As CSharpCodeProvider = New CSharpCodeProvider()
' Build the parameters for source compilation.
Dim cp As New CompilerParameters()
' Add an assembly reference.
cp.ReferencedAssemblies.Add("System.dll")
' Save the assembly as a physical file.
cp.GenerateInMemory = False
' Generate an executable instead of a class library.
cp.GenerateExecutable = True
' Set the assembly file name to generate.
cp.OutputAssembly = exeFile
' 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)
Dim ce As System.CodeDom.Compiler.CompilerError
For Each ce 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;
}
}
Compatibilidad inicial para lenguajes
.NET Framework dispone de compiladores y generadores de código para los siguientes lenguajes: C#, Visual Basic, C++, J# y JScript. La compatibilidad de CodeDOM se puede ampliar a otros idiomas implementando generadores y compiladores de código específicos.