Можно ли сериализовать блок кода C#?

Я использую C# с .СЕТЬ 3.5. Можно ли сериализовать блок кода, передать его куда-нибудь, десериализовать, а затем выполнить?

Пример использования этого:

Action<object> pauxPublish = delegate(object o)
{
    if (!(o is string))
    {
        return;
    }
    Console.WriteLine(o.ToString());
};
Transmitter.Send(pauxPublish);

С какой-то удаленной программой, выполняющей:

var action = Transmitter.Recieve();
action("hello world");

Моя конечная цель - иметь возможность выполнять произвольный код в другом процессе (который не знает код заранее).

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

Basic 16.08.2015 07:35
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
23
1
4 184
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Скомпилируйте его в отдельную сборку, отправьте сборку, пусть другой процесс загрузит ее.

Вы можете подумать о последствиях для безопасности.

Обновлять: другая идея - создать дерево выражений и использовать эту библиотеку для его сериализации:

http://www.codeplex.com/metalinq/

Вы также можете отправить его в виде строки, а затем использовать CodeDomProvider для ее компиляции, результат тот же. У меня есть пример кода:

using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using Microsoft.CSharp;

namespace DynamicCodeApplication
{
    class azCodeCompiler
    {
        private List<string> assemblies;

        public azCodeCompiler()
        {
            assemblies = new List<string>();
            scanAndCacheAssemblies();
        }

        public Assembly BuildAssembly(string code)
        {

            CodeDomProvider prov = CodeDomProvider.CreateProvider("CSharp");
            string[] references = new string[] { };   // Intentionally empty, using csc.rsp
            CompilerParameters cp = new CompilerParameters(references)
                                        {
                                            GenerateExecutable = false,
                                            GenerateInMemory = true
                                        };
            string path = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory();
            cp.CompilerOptions = "@" + path + @"\csc.rsp";
            CompilerResults cr = prov.CompileAssemblyFromSource(cp, code);

            foreach (CompilerError err in cr.Errors)
            {
                Console.WriteLine(err.ToString());
            }
            return cr.CompiledAssembly;
        }

        public object ExecuteCode(string code,
                                  string namespacename, string classname,
                                  string functionname, bool isstatic, params object[] args)
        {
            object returnval = null;
            Assembly asm = BuildAssembly(code);
            object instance = null;
            Type type = null;
            if (isstatic)
            {
                type = asm.GetType(namespacename + "." + classname);
            }
            else
            {
                instance = asm.CreateInstance(namespacename + "." + classname);
                type = instance.GetType();
            }
            MethodInfo method = type.GetMethod(functionname);
            returnval = method.Invoke(instance, args);
            return returnval;
        }

        private void scanAndCacheAssemblies()
        {

            /*
            foreach (string str in Directory.GetFiles(@"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727"))
            {
                if (str.Contains(".dll"))
                {
                    foreach (string st in str.Split(new char[] { '\\' }))
                    {
                        if (st.Contains(".dll"))
                        {
                            assemblies.Add(st);
                        }
                    }
                }
            }
             * */

            assemblies.Add("Accessibility.dll");
            assemblies.Add("AspNetMMCExt.dll");
            assemblies.Add("cscompmgd.dll");
            assemblies.Add("CustomMarshalers.dll");
            assemblies.Add("IEExecRemote.dll");
            assemblies.Add("IEHost.dll");
            assemblies.Add("IIEHost.dll");
            assemblies.Add("Microsoft.Build.Conversion.dll");
            assemblies.Add("Microsoft.Build.Engine.dll");
            assemblies.Add("Microsoft.Build.Framework.dll");
            assemblies.Add("Microsoft.Build.Tasks.dll");
            assemblies.Add("Microsoft.Build.Utilities.dll");
            assemblies.Add("Microsoft.Build.VisualJSharp.dll");
            assemblies.Add("Microsoft.CompactFramework.Build.Tasks.dll");
            assemblies.Add("Microsoft.JScript.dll");
            assemblies.Add("Microsoft.VisualBasic.Compatibility.Data.dll");
            assemblies.Add("Microsoft.VisualBasic.Compatibility.dll");
            assemblies.Add("Microsoft.VisualBasic.dll");
            assemblies.Add("Microsoft.VisualBasic.Vsa.dll");
            assemblies.Add("Microsoft.Vsa.dll");
            assemblies.Add("Microsoft.Vsa.Vb.CodeDOMProcessor.dll");
            assemblies.Add("Microsoft_VsaVb.dll");
            assemblies.Add("mscorlib.dll");
            assemblies.Add("sysglobl.dll");
            assemblies.Add("System.configuration.dll");
            assemblies.Add("System.Configuration.Install.dll");
            assemblies.Add("System.Data.dll");
            assemblies.Add("System.Data.OracleClient.dll");
            assemblies.Add("System.Data.SqlXml.dll");
            assemblies.Add("System.Deployment.dll");
            assemblies.Add("System.Design.dll");
            assemblies.Add("System.DirectoryServices.dll");
            assemblies.Add("System.DirectoryServices.Protocols.dll");
            assemblies.Add("System.dll");
            assemblies.Add("System.Drawing.Design.dll");
            assemblies.Add("System.Drawing.dll");
            assemblies.Add("System.EnterpriseServices.dll");
            assemblies.Add("System.Management.dll");
            assemblies.Add("System.Messaging.dll");
            assemblies.Add("System.Runtime.Remoting.dll");
            assemblies.Add("System.Runtime.Serialization.Formatters.Soap.dll");
            assemblies.Add("System.Security.dll");
            assemblies.Add("System.ServiceProcess.dll");
            assemblies.Add("System.Transactions.dll");
            assemblies.Add("System.Web.dll");
            assemblies.Add("System.Web.Mobile.dll");
            assemblies.Add("System.Web.RegularExpressions.dll");
            assemblies.Add("System.Web.Services.dll");
            assemblies.Add("System.Windows.Forms.dll");
            assemblies.Add("System.XML.dll");
            assemblies.Add("vjscor.dll");
            assemblies.Add("vjsjbc.dll");
            assemblies.Add("vjslib.dll");
            assemblies.Add("vjslibcw.dll");
            assemblies.Add("vjssupuilib.dll");
            assemblies.Add("vjsvwaux.dll");
            assemblies.Add("vjswfc.dll");
            assemblies.Add("VJSWfcBrowserStubLib.dll");
            assemblies.Add("vjswfccw.dll");
            assemblies.Add("vjswfchtml.dll");
            assemblies.Add("Accessibility.dll");
            assemblies.Add("AspNetMMCExt.dll");
            assemblies.Add("cscompmgd.dll");
            assemblies.Add("CustomMarshalers.dll");
            assemblies.Add("IEExecRemote.dll");
            assemblies.Add("IEHost.dll");
            assemblies.Add("IIEHost.dll");
            assemblies.Add("Microsoft.Build.Conversion.dll");
            assemblies.Add("Microsoft.Build.Engine.dll");
            assemblies.Add("Microsoft.Build.Framework.dll");
            assemblies.Add("Microsoft.Build.Tasks.dll");
            assemblies.Add("Microsoft.Build.Utilities.dll");
            assemblies.Add("Microsoft.Build.VisualJSharp.dll");
            assemblies.Add("Microsoft.CompactFramework.Build.Tasks.dll");
            assemblies.Add("Microsoft.JScript.dll");
            assemblies.Add("Microsoft.VisualBasic.Compatibility.Data.dll");
            assemblies.Add("Microsoft.VisualBasic.Compatibility.dll");
            assemblies.Add("Microsoft.VisualBasic.dll");
            assemblies.Add("Microsoft.VisualBasic.Vsa.dll");
            assemblies.Add("Microsoft.Vsa.dll");
            assemblies.Add("Microsoft.Vsa.Vb.CodeDOMProcessor.dll");
            assemblies.Add("Microsoft_VsaVb.dll");
            assemblies.Add("mscorlib.dll");
            assemblies.Add("sysglobl.dll");
            assemblies.Add("System.configuration.dll");
            assemblies.Add("System.Configuration.Install.dll");
            assemblies.Add("System.Data.dll");
            assemblies.Add("System.Data.OracleClient.dll");
            assemblies.Add("System.Data.SqlXml.dll");
            assemblies.Add("System.Deployment.dll");
            assemblies.Add("System.Design.dll");
            assemblies.Add("System.DirectoryServices.dll");
            assemblies.Add("System.DirectoryServices.Protocols.dll");
            assemblies.Add("System.dll");
            assemblies.Add("System.Drawing.Design.dll");
            assemblies.Add("System.Drawing.dll");
            assemblies.Add("System.EnterpriseServices.dll");
            assemblies.Add("System.Management.dll");
            assemblies.Add("System.Messaging.dll");
            assemblies.Add("System.Runtime.Remoting.dll");
            assemblies.Add("System.Runtime.Serialization.Formatters.Soap.dll");
            assemblies.Add("System.Security.dll");
            assemblies.Add("System.ServiceProcess.dll");
            assemblies.Add("System.Transactions.dll");
            assemblies.Add("System.Web.dll");
            assemblies.Add("System.Web.Mobile.dll");
            assemblies.Add("System.Web.RegularExpressions.dll");
            assemblies.Add("System.Web.Services.dll");
            assemblies.Add("System.Windows.Forms.dll");
            assemblies.Add("System.XML.dll");
            assemblies.Add("vjscor.dll");
            assemblies.Add("vjsjbc.dll");
            assemblies.Add("vjslib.dll");
            assemblies.Add("vjslibcw.dll");
            assemblies.Add("vjssupuilib.dll");
            assemblies.Add("vjsvwaux.dll");
            assemblies.Add("vjswfc.dll");
            assemblies.Add("VJSWfcBrowserStubLib.dll");
            assemblies.Add("vjswfccw.dll");
            assemblies.Add("vjswfchtml.dll");


            return;
        }
    }
}

Это было бы большим подспорьем, Таркс, спасибо! Продолжая эту тему, можно ли превратить блок кода C# в строку?

NoizWaves 06.12.2008 12:25

Другой вариант - использовать DLR и ограничить выполнение кода ...

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

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

Безусловно, вы не можете доверять вызывающему абоненту, который действительно может предложить DSL. Взгляните на MGrammar и Осло.

justin.m.chase 07.12.2008 09:13

Выполнение произвольного кода и / или сохранение его где-нибудь в базе данных ... что может пойти не так? Мне это не кажется антипаттерном ;-)

Jacobs Data Solutions 01.07.2010 16:27

Вы можете попробовать использовать IronPython в своем проекте. Это банальный, чтобы делать то, что вы просите в Python. Код Python может вызывать ваши методы C#. Что касается безопасности, вы можете выполнить код в какой-либо ограниченной среде (один из примеров - RestrictedPython).

Это интересная задача, но вы, вероятно, должны описать, почему вы хотите это сделать, поскольку существует множество разных подходов в зависимости от вашей цели. Как отмечает Хампол, есть также довольно серьезные проблемы с безопасностью.

«Сериализованный код» может быть просто исходным кодом или скомпилированной сборкой, в зависимости от ваших требований. Вам, вероятно, не нужно использовать отдельный формат сериализации кода.

Если вы хотите динамически генерировать код и передавать его, вы можете сгенерировать код с помощью CodeDOM и скомпилировать его. Однако вам, скорее всего, не нужно генерировать полностью произвольный код.

Ответ принят как подходящий

ДА!!!

Мы сделали это для очень реального случая производительности. Делать это во время выполнения или использовать DSL было невозможно из-за производительности.

Мы компилируем код в сборку и извлекаем IL из метода. Затем мы получаем все метаданные, связанные с этим методом, и сериализуем весь беспорядок через XML, сжимаем его и помещаем в нашу базу данных.

Во время регидратации мы заново составляем IL с метаданными, используя класс DynamicMethod, и выполняем его.

Мы делаем это из-за скорости. У нас есть тысячи маленьких блоков кода. К сожалению, для компиляции блока кода и его запуска «на лету» требуется не менее 250 мс, что для нас слишком медленно. Мы выбрали этот подход, и он ДЕЙСТВИТЕЛЬНО работает. Во время выполнения требуется неизмеримое количество времени, чтобы воссоздать метод и запустить его.

Единственное, за чем следует следить ... Подписанные сборки и неподписанные сборки не могут смешивать сериализованные данные метода.

Это был метод, который я придумал и над которым работаю. Самая большая проблема, по-видимому, заключается в преобразовании байтового массива, который MethodBody передает, в OpCodes для использования с Reflection.Emit. Я смотрю на weblogs.asp.net/rosherove/archive/2006/04/25/…, который может помочь.

ICR 06.12.2008 17:12

o0o это похоже на подход, который я ищу. Если у вас есть еще ресурсы, относящиеся к Think, мы будем очень благодарны за ссылки :)

NoizWaves 06.12.2008 17:38

Я не могу решить, было ли то, что вы сделали, потрясающим или ужасным. Возможно и то, и другое.

Anthony 06.12.2008 17:54
blogs.msdn.com/haibo_luo/archive/2006/11/07/… также кажется довольно полезным, возможно, даже более полезным.
ICR 06.12.2008 19:24

Удивительно или ужасно? Я думаю, и то и другое. Я действительно ничего не могу сделать, но думаю, что это грандиозный взлом ... Я был поражен, когда он наконец сработал ... потрясен тем, насколько злобным / сложным было решение.

Brian Genisio 06.12.2008 21:59

Мы основали наш подход на этой статье: codeproject.com/KB/cs/ExpressionEval.aspx. Я должен добавить, что, поскольку мы внедрили его (с ТОННОЙ модульных тестов), у нас не было ни одной проблемы с этим подходом.

Brian Genisio 06.12.2008 22:01

Другие вопросы по теме