2010-07-06 13 views
19

Me preguntaba si era posible compilar y ejecutar código almacenado, sin generar un exe o cualquier otro tipo de archivos, básicamente ejecutar el archivo desde la memoria.¿Compila y ejecuta código dinámico sin generar EXE?

Básicamente, la aplicación Principal tendrá un código almacenado (código que potencialmente se modificará) y necesitará compilar el código y ejecutarlo. sin crear ningún archivo.

crear los archivos, ejecutar el programa y luego eliminar los archivos no es una opción. el código compilado deberá ejecutarse desde la memoria.

ejemplos de código, o punteros, o casi cualquier cosa es bienvenida :)

Respuesta

29
using (Microsoft.CSharp.CSharpCodeProvider foo = 
      new Microsoft.CSharp.CSharpCodeProvider()) 
{ 
    var res = foo.CompileAssemblyFromSource(
     new System.CodeDom.Compiler.CompilerParameters() 
     { 
      GenerateInMemory = true 
     }, 
     "public class FooClass { public string Execute() { return \"output!\";}}" 
    ); 

    var type = res.CompiledAssembly.GetType("FooClass"); 

    var obj = Activator.CreateInstance(type); 

    var output = type.GetMethod("Execute").Invoke(obj, new object[] { }); 
} 

Esto compila una clase simple de la cadena de código fuente incluida, luego crea una instancia de la clase e invoca reflexivamente una función en ella.

+5

'GenerateInMemory = true' no hace lo que su nombre sugiere; genera un ensamblado en el directorio temporal que debe eliminar una vez que haya terminado. –

+1

@Tim: admitiré que no estoy familiarizado con el CodeDom, pero no he podido encontrar ninguna evidencia que respalde esto (en mi disco duro en el directorio 'temp' o en el directorio de la aplicación, ni en la web en una búsqueda rápida). ¿Podría indicarme un recurso que pueda confirmar esto? –

+2

OK - La última vez que hice esto, debo haber guardado los ensamblados en el disco para la depuración. Puedo ver que 'CSharpCodeProvider' se compila en un archivo temporal, carga ese archivo usando' Assembly.Load (byte []) ', luego lo elimina. (No puede eludir por completo el archivo temporal porque ejecuta _csc.exe_ debajo.) –

1

Sí, se puede hacer esto. Es muy lento, pero ciertamente puedes hacerlo. Mire CodeDOM o (new CSharpCodeProvider().CreateCompiler()) en .Net.

1

Mire en System.CodeDom. Hará exactamente lo que estás buscando.

+0

'System.CodeDom' es la opción más agradable, pero todavía invoca el compilador y genera una asamblea en la carpeta temporal –

3

Es posible. Es fácil o difícil, dependiendo de cuánto y qué tipo de código desea escribir.

Editar: Tenga en cuenta que, antes de la .NET 4.0, System.Linq.Expressions está limitado a lo que puede caber en una sola línea de C#: es decir, no si, mientras, la asignación de variables, etc.

+0

No sea tan rápido para decir' System.Linq.Expressions' es limitado. Aunque no tiene el poder de 'System.Reflection.Emit', he compilado programas masivos con él. La capacidad de ver el árbol de expresiones en una vista de depuración es extremadamente útil. – ChaosPandion

+0

Me gusta 'System.Linq.Expressions' mucho :). Es solo que, antes de .NET 4.0, está limitado a lo que puede caber en una sola línea de C# (es decir, no 'if',' while', asignación de variables, etc.) –

+0

@Tim - Oh, eso tiene más sentido. Solo lo he usado en .NET 4.0. – ChaosPandion

-1

También eche un vistazo a la incrustación de un lenguaje de scripts como Python, Ruby, Lua, etc. Todos soportan la ejecución del código de la memoria sin que nada se escriba en el disco.

+0

Esto debería haber sido un comentario. – caesay

+0

Lo consideraría una respuesta. (Ver el mío a continuación.) –

4

Aquí hay un ejemplo de cómo usar System.Linq.Expressions para agregar a la respuesta de Tim. Obviamente, no es el código más bonito, pero tenerlo en esta bonita forma de árbol hace que el desarrollo sea tan fácil.

private Expression<IsWordChar> CreateIsWordCharExpression() 
{ 
    var e = Expression.Parameter(typeof(int), "e"); 
    var c = Expression.Variable(typeof(char), "c"); 
    var returnLabel = Expression.Label(Expression.Label(typeof(bool)), _falseConstant); 
    var lambda = Expression.Lambda<IsWordChar>(
     Expression.Block(
      new[] { c }, 
      Expression.IfThen(
       Expression.OrElse(
        Expression.Equal(e, Expression.Constant(-1)), 
        Expression.Equal(e, _inputLengthVar) 
       ), 
       Expression.Return(returnLabel.Target, _falseConstant) 
      ), 
      Expression.Assign(c, Expression.MakeIndex(_str, _stringCharsPropertyInfo, new[] { e })), 
      Expression.IfThenElse(
       Expression.OrElse(
        Expression.OrElse(
         Expression.OrElse(
          Expression.AndAlso(
           Expression.GreaterThanOrEqual(c, Expression.Constant('a')), 
           Expression.LessThanOrEqual(c, Expression.Constant('z')) 
          ), 
          Expression.AndAlso(
           Expression.GreaterThanOrEqual(c, Expression.Constant('A')), 
           Expression.LessThanOrEqual(c, Expression.Constant('Z')) 
          ) 
         ), 
         Expression.AndAlso(
          Expression.GreaterThanOrEqual(c, Expression.Constant('0')), 
          Expression.LessThanOrEqual(c, Expression.Constant('1')) 
         ) 
        ), 
        Expression.Equal(c, Expression.Constant('_')) 
       ), 
       Expression.Return(returnLabel.Target, _trueConstant), 
       Expression.Return(returnLabel.Target, _falseConstant) 
      ), 
      returnLabel 
     ), 
     "IsWordChar", 
     new[] { e } 
    ); 
    return lambda; 
} 
-2

Es difícil, si no imposible compilar y ejecutar C# sin crear un archivo, porque ... Bueno, eso es lo que es- compilación convertir una lengua en un archivo ejecutable. Lo que estás buscando es algún tipo de funcionalidad de scripting. Lo que describió en su pregunta es esencialmente la diferencia entre un idioma interpretado y un compilado en el idioma. Ver Wikipedia: Scripting language.

Dependiendo de para qué utilizará esta función, puede hacer un gran uso de un lenguaje de scripts como Python, Ruby o Lua. He aquí un ejemplo: How do I run a Python script from C#?

Esto haría dependiente de su aplicación sobre python.exe (o lo que sea ejecutable que había necesidad de ejecutar el lenguaje de programación que elija).Si desea evitar eso, puede que no sea demasiado difícil crear su propio lenguaje de scripting para el cual su aplicación realiza el tiempo de ejecución, dependiendo de lo que necesite hacer con su script insertado.

Editar: Ese primer párrafo es basura. Lo siento. Consulte http://msdn.microsoft.com/en-us/library/8ffc3x75%28v=vs.110%29.aspx

+1

Gracias por esto. C# se compila en MSIL, y asumo que la forma en que .Net manejaría MSIL es muy similar a cómo otros lenguajes interpretados manejan esto. Crear una dependencia a otro tiempo de ejecución fue imposible para mí, y crear mi propio lenguaje de scripting fue demasiado trabajo para la relevancia de la aplicación. Terminé simplemente escribiendo el código IL y emitiéndolo. De esta forma, básicamente obtengo un lenguaje de scripting que se puede ejecutar por el tiempo de ejecución .Net y puedo convertir de ida y vuelta a C# si es necesario (aunque casi nunca lo es). – caesay

+2

Eso es una tontería. La compilación no significa automáticamente en el disco. muchos sistemas compilan código en la memoria y luego lo almacenan allí para su ejecución. – user430788

+0

@ user430788, tienes razón, pero me refería a hacer esto con C#, que no es posible (mira los comentarios sobre la pregunta marcada como respuesta, incluso compilando "en memoria" usa csc.exe y crea un archivo temporal) . Bueno, supongo que es posible, pero necesitaría algo para procesar C# como lo hace csc.exe, y luego ejecutarlo sin hacer un archivo. Esencialmente un csc.exe homebrew, que sería increíblemente más complicado que solo usar algún tipo de scripting. Sin embargo, sería bastante impresionante :) –

0

En Mono, utiliza CSharp.Evaluator. Funciona verdaderamente en la memoria v. Algunas de las otras soluciones mencionadas que se escriben y leen en un archivo debajo del capó.

Cuestiones relacionadas