Как выполнить код, который находится в строке? [дубликат]

Вопрос или проблема

Предположим, у меня есть нечто подобное:

string singleStatement = "System.DateTime.Now";

Есть ли способ взять singleStatement и разобрать и выполнить его во время выполнения?

Так что:

DateTime currentTime = singleStatement.SomeCoolMethodToRunTheText();

присвоило бы значение DateTime.Now переменной currentTime.

Посмотрите это (цитата ниже).

Это возможно: посмотрите на System.CodeDom и System.CodeDom.Compiler.

Я нашел пример, который написал несколько месяцев назад:
предположим, usingList – это arraylist со всеми операторными указателями (без ключевого слова using, System.Xml например)
предположим, importList – это arraylist со всеми именами dll, которые необходимы для компиляции (system.dll например)
предположим, source – это исходный код, который вы хотите скомпилировать
предположим, classname – это имя класса, который вы хотите скомпилировать
предположим, methodname – это имя метода

Посмотрите на следующий код:

//Создание метода
CodeMemberMethod pMethod = new CodeMemberMethod();
pMethod.Name = methodname;
pMethod.Attributes = MemberAttributes.Public;
pMethod.Parameters.Add(new
CodeParameterDeclarationExpression(typeof(string[]),"boxes"));
pMethod.ReturnType=new CodeTypeReference(typeof(bool));
pMethod.Statements.Add(new CodeSnippetExpression(@"
bool result = true;
try
{
    " + source + @"
}
catch
{
    result = false;
}
return result;
"));

//Создание класса
CodeTypeDeclaration pClass = 
  new System.CodeDom.CodeTypeDeclaration(classname);
pClass.Attributes = MemberAttributes.Public;
pClass.Members.Add(pMethod);
//Создание пространства имен
CodeNamespace pNamespace = new CodeNamespace("myNameSpace");
pNamespace.Types.Add(pClass);
foreach(string sUsing in usingList)
  pNamespace.Imports.Add(new
    CodeNamespaceImport(sUsing));

//Создание единицы компиляции
CodeCompileUnit pUnit = new CodeCompileUnit();
pUnit.Namespaces.Add(pNamespace);
//Установка параметров компиляции
CompilerParameters pParams = 
  new CompilerParameters((string[])importList.ToArray(typeof(string)));
pParams.GenerateInMemory = true;
//Компиляция
CompilerResults pResults =
  (new CSharpCodeProvider())
    .CreateCompiler().CompileAssemblyFromDom(pParams, pUnit);

if (pResults.Errors != null && pResults.Errors.Count>0)
{
    foreach(CompilerError pError in pResults.Errors)
      MessageBox.Show(pError.ToString());
    result =
    pResults.CompiledAssembly.CreateInstance("myNameSp ace."+classname);
}

Например,

если 'usingList' равно
{
    "System.Text.RegularExpressions"
}
если 'importList' равно
{
    "System.dll"
}
если 'classname' равно "myClass"
если 'methodName' равно "myMethod"
если 'source' равно "
string pays=@"ES
FR
EN
"
Regex regex=new Regex(@"^[A-Za-z]
{
    2
}
$");
result=regex.IsMatch(boxes[0]);
if (result)
{
    regex=new Regex(@"^"+boxes[0]+@".$",RegexOptions.Multiline);
    result=regex.Matches(pays).Count!=0;
}

Тогда код, который будет скомпилирован, будет следующим:

using System.Text.RegularExpressions;
namespace myNameSpace
{
    public class myClass
    {
        public bool myMethod(string[] boxes)
        {
            bool result=true;
            try
            {
                string pays=@"ES
                FR
                EN
                "
                Regex regex=new Regex(@"^[A-Za-z]
                {
                    2
                }
                $");
                result=regex.IsMatch(boxes[0]);
                if (result)
                {
                    regex=new Regex(@"^"+boxes[0]+@".$",RegexOptions.Multiline);
                    result=regex.Matches(pays).Count!=0;
                }
            }
            catch
            {
                result=false;
            }
            return result;
        }
    }
}

Это возможно только с использованием сервисов компилятора и Reflection.Emit(), которые будут компилировать и загружать сборку в память.

Посмотрите здесь.

http://www.c-sharpcorner.com/UploadFile/puranindia/419/

Вы можете компилировать код во время выполнения, используя объект CSharpCodeProvider. Хотите ли вы действительно это сделать или нет, вопрос спорный. 🙂

Ответ или решение

Вопрос о том, как выполнить код, который находится в строке, является интересным и многогранным в контексте программирования на языке C#. Чтобы успешно решить данную задачу, необходимо использовать возможности, предоставляемые библиотекой .NET, такие как CodeDom и CSharpCodeProvider. Рассмотрим этот процесс более подробно.

Основные понятия

Когда нам нужно выполнить строку кода в C#, мы сталкиваемся с задачей динамической компиляции и выполнения. Самый распространенный способ это сделать — использовать класс CSharpCodeProvider из пространства имен System.CodeDom.Compiler. Этот класс позволяет генерировать и компилировать C# код на лету.

Шаги выполнения кода из строки

  1. Сбор информации: Определите необходимые директивы using, имена классов и методов, а также код, который вам необходимо скомпилировать и выполнить.

  2. Создание структуры кода: Используйте классы CodeNamespace, CodeTypeDeclaration, и CodeMemberMethod для создания кода, который будет скомпилирован.

  3. Компиляция кода: Используйте метод CompileAssemblyFromDom для компиляции созданного кода.

  4. Выполнение кода: После успешной компиляции вы можете создать экземпляр класса и вызвать нужные методы.

Вот пример того, как это можно сделать:

using System;
using System.CodeDom.Compiler;
using System.CodeDom;
using Microsoft.CSharp;

public class DynamicCodeExecutor
{
    public static object ExecuteCode(string code, string className, string methodName)
    {
        // Создаем пространство имен и класс
        CodeNamespace codeNamespace = new CodeNamespace("DynamicNamespace");
        CodeTypeDeclaration codeClass = new CodeTypeDeclaration(className);

        // Создаем метод
        CodeMemberMethod codeMethod = new CodeMemberMethod();
        codeMethod.Name = methodName;
        codeMethod.ReturnType = new CodeTypeReference(typeof(object));

        // Добавляем код, который будет выполняться в методе
        codeMethod.Statements.Add(new CodeSnippetExpression(code));
        codeClass.Members.Add(codeMethod);
        codeNamespace.Types.Add(codeClass);

        // Создаем компиляционную единицу
        CodeCompileUnit codeUnit = new CodeCompileUnit();
        codeUnit.Namespaces.Add(codeNamespace);

        // Параметры компиляции
        CompilerParameters parameters = new CompilerParameters
        {
            GenerateInMemory = true
        };
        parameters.ReferencedAssemblies.Add("mscorlib.dll");
        parameters.ReferencedAssemblies.Add("System.dll");

        // Компилируем код
        CSharpCodeProvider provider = new CSharpCodeProvider();
        CompilerResults results = provider.CompileAssemblyFromDom(parameters, codeUnit);

        // Проверяем на наличие ошибок компиляции
        if (results.Errors.Count > 0)
        {
            foreach (CompilerError error in results.Errors)
            {
                Console.WriteLine($"Error ({error.ErrorNumber}): {error.ErrorText}");
            }
            return null;
        }

        // Создаем экземпляр и вызываем метод
        object obj = results.CompiledAssembly.CreateInstance($"DynamicNamespace.{className}");
        return obj.GetType().GetMethod(methodName)?.Invoke(obj, null);
    }
}

class Program
{
    static void Main()
    {
        string code = "return DateTime.Now;";  // Код для выполнения
        object result = DynamicCodeExecutor.ExecuteCode(code, "DynamicClass", "DynamicMethod");
        Console.WriteLine(result);
    }
}

Объяснение кода

  • CodeNamespace и CodeTypeDeclaration — обеспечивают создание структуры пространств имен и классов.
  • CodeMemberMethod — определяет метод, который будет содержать выполненный код.
  • CodeSnippetExpression — используется для добавления произвольного кода.
  • CompileAssemblyFromDom — компилирует сгенерированный код и возвращает объект CompilerResults, содержащий информацию о результате компиляции.
  • CreateInstance и Invoke — используются для создания экземпляра скомпилированного класса и вызова метода.

Безопасность

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

Заключение

Выполнение кода из строки в C# — задача, требующая внимательного подхода и правильного использования средств компиляции. Подход, описанный выше, предоставляет мощные инструменты для динамического выполнения программного кода, и при этом позволяет гибко управлять созданием и контролем выполнения кода.

Оцените материал
Добавить комментарий

Капча загружается...