Компилировать и запускать динамический код, не генерируя EXE? - PullRequest
22 голосов
/ 06 июля 2010

Мне было интересно, можно ли скомпилировать и запустить хранимый код, не создавая exe или любой другой тип файлов, в основном запустить файл из памяти.

По сути, основное приложение будет иметьнекоторый сохраненный код (код, который потенциально может быть изменен), и он должен будет скомпилировать код и выполнить его.без создания каких-либо файлов.

создание файлов, запуск программы, а затем удаление файлов не вариант.скомпилированный код нужно будет запускать из памяти.

примеры кода, или указатели, или почти все приветствуется:)

Ответы [ 8 ]

35 голосов
/ 06 июля 2010
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[] { });
}

Это компилирует простой класс из включенной строки исходного кода, затем создает экземпляр класса и рефлексивно вызывает функцию для него.

5 голосов
/ 06 июля 2010

Вот пример того, как использовать System.Linq.Expressions, чтобы добавить к ответу Тима.Очевидно, что это не самый красивый код, но наличие его в этой красивой древовидной форме делает разработку настолько простой.

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;
}
4 голосов
/ 06 июля 2010

Это возможно. Это легко или сложно, в зависимости от того, сколько и какой код вы хотите написать.

  • Компиляция однострочных выражений: System.Linq.Expressions (просто, но ограниченно)
  • Компиляция целых программ: System.Reflection.Emit (сложно отладить, но не невозможно)

Редактировать: Обратите внимание, что до .NET 4.0, System.Linq.Expressions ограничен тем, что вы можете поместить в одну строку C #: то есть, нет, если, в то время, назначение переменных и т. Д.

1 голос
/ 06 июля 2010

Посмотрите на System.CodeDom.Он будет делать именно то, что вы ищете.

1 голос
/ 06 июля 2010

Да, вы можете сделать это.Это очень медленно, но вы, безусловно, можете это сделать.Посмотрите на CodeDOM или (new CSharpCodeProvider().CreateCompiler()) в .Net.

0 голосов
/ 11 ноября 2014

В Mono вы используете CSharp.Evaluator. Он действительно работает в памяти v. Некоторые другие упомянутые решения, которые записывают и читают в файле под капотом.

0 голосов
/ 19 февраля 2014

Сложно, если вообще невозможно, скомпилировать и выполнить C # без создания файла, потому что ... Ну, вот что такое компиляция - превращение языка в исполняемый файл.То, что вы ищете, это какая-то функциональность сценариев.То, что вы описали в своем вопросе, по сути, является разницей между интерпретируемым языком и скомпилированным языком.См. Википедия: язык сценариев .

В зависимости от того, для чего вы будете использовать эту функцию, вы можете широко использовать язык сценариев, такой как Python, Ruby или Lua.Вот пример: Как запустить скрипт Python из C #?

Это сделает вашу программу зависимой от python.exe (или любого исполняемого файла, который вам понадобится для запуска языка сценариев, который вывыбирать).Если вы хотите этого избежать, может быть не сложно создать свой собственный язык сценариев, для которого ваше приложение выполняет среду выполнения, в зависимости от того, что вам нужно делать с внедренным сценарием.

Редактировать:Этот первый абзац - мусор.Сожалею.Смотри http://msdn.microsoft.com/en-us/library/8ffc3x75%28v=vs.110%29.aspx

0 голосов
/ 06 июля 2010

Также обратите внимание на встраивание языка сценариев, такого как Python, Ruby, Lua и т. Д., Все они поддерживают выполнение кода из памяти без записи на диск.

...