Выполнение кода из textbox

236
15 августа 2017, 12:01

Помогите реализовать такую идею:
Ввожу в textbox1 определенный код и при нажатии на кнопку он выполняется.
Идеи с if(...) не подойдут

Например:
Ввожу в textbox: MessageBox.Show("Сообщение");
Нажимаю на кнопку
И выполняется этот код

Answer 1

А давайте воспользуемся новомодным Roslyn API.

Для начала, нам понадобится nuget-пакет Microsoft.CodeAnalysis.CSharp.Scripting, добавьте его через References → правая кнопка мыши → Manage NuGet Packages....

Теперь, сам скрипт. Модельный класс будет очень простым, т. к. всё уже написано за нас:

using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
class Script
{
    ScriptState state;
    public static async Task<Script> Create(
        IEnumerable<Assembly> references, IEnumerable<string> usings)
    {
        var options = ScriptOptions.Default.WithReferences(references).WithImports(usings);
        var state = await CSharpScript.RunAsync("", options);
        return new Script() { state = state };
    }
    public async Task<object> ExecuteNext(string code)
    {
        state = await state.ContinueWithAsync(code);
        return state.ReturnValue;
    }
}

Вот собственно и вся сложность.

Пользоваться так:

// какие DLL должны быть доступны?
static Assembly[] references = new[]
    {
        typeof(object).Assembly,
        typeof(Uri).Assembly,
        typeof(Enumerable).Assembly,
        typeof(MessageBox).Assembly
    };
// какие юзинги должны быть доступны?
static string[] usings = new[]
    {
        "System",
        "System.IO",
        "System.Text",
        "System.Windows"
    };
// инициализация
Script script = await Script.Create(references, usings);
// выполнение одной команды:
try
{
    var result = await script.ExecuteNext(cmd);
    LastResult = result?.ToString() ?? "<no output>";
    IsLastGood = true;
}
catch (CompilationErrorException ex)
{
    LastResult = string.Join(" // ", ex.Diagnostics);
    IsLastGood = false;
}

Я прикрутил простейший интерфейс, выглядит так:

Проект лежит здесь: https://github.com/vladd/EvalUITest

Различная полезная литература:

  • Scripting API Samples
  • In-memory C# compilation (and .dll generation) using Roslyn
  • Getting Started C# Syntax Analysis
  • Compiling C# Code Into Memory and Executing It with Roslyn
Answer 2
private void btnCompile_Click(object sender, EventArgs e)
{
    // Здесь код из твоего TextBox'а
    string code =
        @"class EntityCollection : System.Collections.Generic.List<Entity> {}
        class Entity
        {
        public string Name { get; set; }
            public int Age { get; set; }
        }";
    // Получаем интерфейс компилятора
    CSharpCodeProvider codeProvider = new CSharpCodeProvider();
    // Задаём параметры компиляции
    CompilerParameters compilerParameters = new CompilerParameters();
    compilerParameters.GenerateInMemory = true;
    compilerParameters.TreatWarningsAsErrors = false;
    compilerParameters.WarningLevel = 4;
    // Цепляем референсные сборки
    compilerParameters.ReferencedAssemblies.Add("System.dll");
    // Компилируем код
    CompilerResults results = codeProvider.CompileAssemblyFromSource(compilerParameters, code);
    if (results.Errors.Count > 0)
    {
        StringBuilder sbExceptions = new StringBuilder();
        foreach (CompilerError CompErr in results.Errors)
        {
            sbExceptions.AppendLine(
                "Line number " + CompErr.Line +
                ", Error Number: " + CompErr.ErrorNumber +
                ", ‘" + CompErr.ErrorText + ";" +
                Environment.NewLine + Environment.NewLine);
        }
        throw new Exception("Exception raised while compiling your code: nn" + sbExceptions);
    }
    // Получаем скопилированную сборку
    Assembly assembly = results.CompiledAssembly;
    // Ищем наш тип "EntityCollection"
    Type type = assembly.GetType("EntityCollection");
    // Создаём экземпляр этого класса
    IList list = (IList) Activator.CreateInstance(type);
    // Ищем наш второй тип и порождаем его экземпляр
    Type eType = assembly.GetType("Entity");
    object obj = Activator.CreateInstance(eType);
    // Задаём его свойства
    eType.GetProperty("Name").SetValue(obj, "Sanjay", null);
    eType.GetProperty("Age").SetValue(obj, 30, null);
    // Добавляем в нашу же коллецию
    list.Add(obj);
    // Делаем с ней что-нибудь
    dataGridView1.DataSource = list;
}

Исходная статья здесь.

READ ALSO
WPF Приложение под MAC OS

WPF Приложение под MAC OS

Есть приложение на WPF, которое отлично работает под Windows но требуется также портировать под MAC OSВозможно ли такое средствами Visual Studio ? Обязательно...

194
Дозапись в файл с блокировкой

Дозапись в файл с блокировкой

Есть файл с которым работает программаОна считывает и записывает в него данные

186