Compiler et exécuter du code dynamique, sans générer D'EXE?

je me demandais s'il était possible de compiler, et d'exécuter du code stocké, sans générer un exe ou tout autre type de fichiers, essentiellement exécuter le fichier de mémoire.

fondamentalement, l'application principale, aura un certain code stocké (code qui sera potentiellement changé), et il aura besoin de compiler le code, et l'exécuter. sans créer de fichiers.

créer les fichiers, exécuter le programme, puis supprimer les fichiers n'est pas une option. le code compilé devra être exécuté de mémoire.

exemples de code, ou des pointeurs, ou à peu près tout est le bienvenue :)

19
demandé sur caesay 2010-07-06 21:57:02

8 réponses

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[] { });
}

cela compile une classe simple à partir de la chaîne de code source incluse, puis instancie la classe et invoque réflectivement une fonction sur elle.

32
répondu Adam Robinson 2010-07-06 18:08:56

Voici un exemple d'utilisation de System.Linq.Expressions pour ajouter à la réponse de Tim. Évidemment, ce n'est pas le plus beau code, mais le fait de l'avoir dans cette belle forme arborescente rend le développement si facile.

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;
}
5
répondu ChaosPandion 2010-07-06 18:21:08

c'est possible. C'est facile ou difficile, selon la quantité et le type de code que vous voulez écrire.

modifier: noter que, avant .net 4.0, System.Linq.Expressions est limité à ce que vous pouvez ajuster sur une seule ligne de C#: c'est-à-dire, non si, tandis que, assignation variable, etc.

4
répondu Tim Robinson 2010-07-06 18:14:55

Oui, vous pouvez le faire. Il est très lent, mais vous pouvez certainement le faire. Regardez le CodeDOM ou le (new CSharpCodeProvider().CreateCompiler()) .Net.

1
répondu Brian Genisio 2010-07-06 17:59:10

regardez dans System.CodeDom . Il va faire exactement ce que vous cherchez.

1
répondu Seattle Leonard 2010-07-06 17:59:35

En Mono vous utilisez CSharp.Évaluateur. Il fonctionne vraiment dans la mémoire v. certaines des autres solutions mentionnées qui écrivent et relisent dans un dossier sous le capot.

0
répondu user430788 2014-11-10 22:26:12

regardez aussi l'intégration d'un langage de script comme Python, Ruby, Lua, etc.. tous ceux qui soutiennent l'exécution de code de la mémoire sans rien être écrit sur le disque.

-1
répondu Jason Miesionczek 2010-07-06 18:11:22

il est difficile, voire impossible de compiler et d'exécuter C# sans créer de fichier, parce que... C'est ce qu'est une compilation - transformer un langage en fichier exécutable. Ce que vous recherchez est une sorte de fonctionnalité de script. Ce que vous avez décrit dans votre question est essentiellement la différence entre un interprété langue et un compilé langue. Voir Wikipedia: langage de script .

selon ce que vous allez utiliser cette fonctionnalité, vous pourriez faire un grand usage d'un langage de script comme Python, Ruby, ou Lua. Voici un exemple: comment exécuter un script Python à partir de C#?

cela rendrait votre application dépendante de python.exe (ou n'importe quel exécutable dont vous avez besoin pour exécuter le langage de script que vous choisissez). Si vous voulez éviter cela, il pourrait ne pas être trop dur de faire votre propre langage de script que votre application n'a l'exécution, en fonction de ce que vous devez faire avec votre script injecté.

Edit: ce premier paragraphe est nul. Désolé. Voir http://msdn.microsoft.com/en-us/library/8ffc3x75%28v=vs.110%29.aspx

-2
répondu Michael Hoffmann 2017-05-23 12:32:17