Загрузка и выполнение DynamicMethod из byte массива
От: qlat  
Дата: 15.07.13 12:39
Оценка:
Цель сохранить байт-код объекта DynamicMethod, и при следующем запуске программы загрузить и выполнить

1. Этап получение байт-кода

Пример
using System.Reflection;
using System.Reflection.Emit;

void f()
{
DynamicMethod d = new DynamicMethod("xxx", typeof(void), null);

ILGenerator il = d.GetILGenerator();
int idx = il.DeclareLocal(typeof(string)).LocalIndex;

il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Ldstr, "Hellow world");
il.Emit(OpCodes.Stloc, idx);
il.Emit(OpCodes.Ldloc, idx);

Type[] t = new Type [1] { typeof(string) };

MethodInfo mi = typeof(Console).GetMethod("WriteLine", t );
Console.WriteLine(mi.MetadataToken.ToString());

il.Emit(OpCodes.Call, mi);
il.Emit(OpCodes.Nop);
mi = typeof(Console).GetMethod("ReadLine");
il.Emit(OpCodes.Call, mi);
il.Emit(OpCodes.Pop);
il.Emit(OpCodes.Ret);

MethodBody mb = d.GetMethodBody();
byte[] src = mb.GetILAsByteArray();

/*
var ilgen = d.GetILGenerator();
var fiBytes = il.GetType().BaseType.GetField("m_ILStream", BindingFlags.Instance | BindingFlags.NonPublic);
var fiLength = il.GetType().BaseType.GetField("m_length", BindingFlags.Instance | BindingFlags.NonPublic);
byte[] code = fiBytes.GetValue(ilgen) as byte[];
int cnt = (int)fiLength.GetValue(ilgen);
byte[] src = new byte[cnt];
Buffer.BlockCopy(code, 0, src, 0, cnt);
*/
}

На строке MethodBody mb = d.GetMethodBody();
возникает Exception — Операция является недопустимой из-за текущего состояния объекта.
Байт-код можно получить другим кодом (см. комментарии), но хочется понять, почему нельзя воспользоваться стандартным решением

2. Как скорректировать байт-код при следующем запуске, чтобы он корректно выполнялся (т.к. в байт-коде указываются фактические ссылки на методы, поля, свойства, строки, которые при новом запуске могут иметь другие адреса)?
Re: Загрузка и выполнение DynamicMethod из byte массива
От: vit_as Россия  
Дата: 15.07.13 18:00
Оценка:
Здравствуйте, qlat, Вы писали:

Q>Цель сохранить байт-код объекта DynamicMethod, и при следующем запуске программы загрузить и выполнить


Q>1. Этап получение байт-кода


Q>Пример

Q>using System.Reflection;
Q>using System.Reflection.Emit;

Q>void f()

Q>{
Q>DynamicMethod d = new DynamicMethod("xxx", typeof(void), null);

Q>ILGenerator il = d.GetILGenerator();

Q>int idx = il.DeclareLocal(typeof(string)).LocalIndex;

Q>il.Emit(OpCodes.Nop);

Q>il.Emit(OpCodes.Ldstr, "Hellow world");
Q>il.Emit(OpCodes.Stloc, idx);
Q>il.Emit(OpCodes.Ldloc, idx);

Q>Type[] t = new Type [1] { typeof(string) };


Q>MethodInfo mi = typeof(Console).GetMethod("WriteLine", t );

Q>Console.WriteLine(mi.MetadataToken.ToString());

Q>il.Emit(OpCodes.Call, mi);

Q>il.Emit(OpCodes.Nop);
Q>mi = typeof(Console).GetMethod("ReadLine");
Q>il.Emit(OpCodes.Call, mi);
Q>il.Emit(OpCodes.Pop);
Q>il.Emit(OpCodes.Ret);

Q>MethodBody mb = d.GetMethodBody();

Q>byte[] src = mb.GetILAsByteArray();

Q>/*

Q>var ilgen = d.GetILGenerator();
Q>var fiBytes = il.GetType().BaseType.GetField("m_ILStream", BindingFlags.Instance | BindingFlags.NonPublic);
Q>var fiLength = il.GetType().BaseType.GetField("m_length", BindingFlags.Instance | BindingFlags.NonPublic);
Q>byte[] code = fiBytes.GetValue(ilgen) as byte[];
Q>int cnt = (int)fiLength.GetValue(ilgen);
Q>byte[] src = new byte[cnt];
Q>Buffer.BlockCopy(code, 0, src, 0, cnt);
Q>*/
Q>}

Q>На строке MethodBody mb = d.GetMethodBody();

Q>возникает Exception — Операция является недопустимой из-за текущего состояния объекта.
Q>Байт-код можно получить другим кодом (см. комментарии), но хочется понять, почему нельзя воспользоваться стандартным решением

Метод GetMethodBody не переопределен в классе DynamicMethod. Вызывается метод базового класса MethodBase

                 public virtual MethodBody GetMethodBody()
        {
            throw new InvalidOperationException();
        }
Re: Загрузка и выполнение DynamicMethod из byte массива
От: qlat  
Дата: 15.07.13 18:48
Оценка:
Как сохранить байт-код объекта DynamicMethod, и при следующем запуске программы загрузить и выполнить.
Может кто решал такую задачу?
Re[2]: Загрузка и выполнение DynamicMethod из byte массива
От: Codechanger Россия  
Дата: 15.07.13 19:50
Оценка:
Здравствуйте, qlat, Вы писали:

Q>Как сохранить байт-код объекта DynamicMethod, и при следующем запуске программы загрузить и выполнить.

Q>Может кто решал такую задачу?

Ну скомпилируйте сборку и не мучайтесь.
Re[3]: Загрузка и выполнение DynamicMethod из byte массива
От: qlat  
Дата: 15.07.13 20:38
Оценка:
Здравствуйте, Codechanger, Вы писали:

C>Здравствуйте, qlat, Вы писали:


Q>>Как сохранить байт-код объекта DynamicMethod, и при следующем запуске программы загрузить и выполнить.

Q>>Может кто решал такую задачу?

C>Ну скомпилируйте сборку и не мучайтесь

возможно так и надо

задачка такая
1. порядка 10000 классов, в каждом классе в среднем по 10 методов
2. каждый метод редактируется и изменяется в runtime
3. классы (методы) загружаются по мере необходимости
4. классы написаны на языке C# с дополнительными возможностями работы с метаданными программы
например с таблицами,

Table1 t1; // table1 — таблица в базе (метаданные в репозитарии программы)

t1.forUpdate(true);
while ( select t1 where t1.Field1 > 100 )
{
t1.Field1 = t1.Field1 + 10;
t1.update();
}

отсюда вопросы
1. каждый класс будет в отдельной сборке? как будет освобождаться память?
2. что будет если я в runtime за 5 минут поменяю 10 раз один метод в классе?
3. как мне сделать загрузку метаданных по мере необходимости?
4. компиляция с метаданными? сейчас я делаю свой простой компилятор, он создает DynamicMethod

думал задача простая взять из него bytearray, сохранить, и повторно использовать, а нет
Re[4]: Загрузка и выполнение DynamicMethod из byte массива
От: Codechanger Россия  
Дата: 16.07.13 06:55
Оценка:
Здравствуйте, qlat, Вы писали:

Q>отсюда вопросы

Q>1. каждый класс будет в отдельной сборке? как будет освобождаться память?
Нет, все классы в одной. Для корректной выгрузки сборки по идее надо работать через AppDomain.
Q>2. что будет если я в runtime за 5 минут поменяю 10 раз один метод в классе?
Ну пока вы не нажмете условную кнопку "Сохранить", ничего не будет.При сохранении должен убиваться старый домен, создаваться новый, и в него грузиться вновь откомпилированная сборка.

На вопросы 3 и 4 у меня однозначного ответа нет. В целом выбранный путь представляется мне довольно странным. Возможно, в вашем случае поможет Roslyn.
Re[5]: Загрузка и выполнение DynamicMethod из byte массива
От: qlat  
Дата: 16.07.13 07:48
Оценка: :))
Здравствуйте, Codechanger, Вы писали:

C>Здравствуйте, qlat, Вы писали:

Q>>отсюда вопросы
Q>>1. каждый класс будет в отдельной сборке? как будет освобождаться память?
C>Нет, все классы в одной. Для корректной выгрузки сборки по идее надо работать через AppDomain.

все 10000 классов? пользователю нужны только 300
если я допустил ошибку в одном методе, вся сборка не будет работать?

Q>>2. что будет если я в runtime за 5 минут поменяю 10 раз один метод в классе?

C>Ну пока вы не нажмете условную кнопку "Сохранить", ничего не будет.При сохранении должен убиваться старый домен, создаваться новый, и в него грузиться вновь откомпилированная сборка.

я нажимаю кнопку сохранить, у меня открыта форма в ней создан объект(класс), который я изменил, что будет в этом случае?

C>На вопросы 3 и 4 у меня однозначного ответа нет. В целом выбранный путь представляется мне довольно странным. Возможно, в вашем случае поможет Roslyn.



Думаю путь, который я уже выбрал правильный. Мне нужно решить конкретную маленькую задачу.
Re: Загрузка и выполнение DynamicMethod из byte массива
От: Sinclair Россия https://github.com/evilguest/
Дата: 17.07.13 07:17
Оценка:
Здравствуйте, qlat, Вы писали:

Q>Цель сохранить байт-код объекта DynamicMethod, и при следующем запуске программы загрузить и выполнить

Неправильная цель. DynamicMethod специально сделан для одноразовых задач и не предназначен для повторного использования.
Единицей сохраняемого кода в .Net является сборка. Читайте в сторону Collectible Assemblies.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Загрузка и выполнение DynamicMethod из byte массива
От: qlat  
Дата: 17.07.13 08:57
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, qlat, Вы писали:


Q>>Цель сохранить байт-код объекта DynamicMethod, и при следующем запуске программы загрузить и выполнить

S>Неправильная цель. DynamicMethod специально сделан для одноразовых задач и не предназначен для повторного использования.
S>Единицей сохраняемого кода в .Net является сборка. Читайте в сторону Collectible Assemblies.

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

Использование Collectible Assemblies, опять оставляет много вопросов.
DynamicMethod мне подходит, достаточно просто сохранить в свой формат все что я создаю в нем на уровне reflection.emit, а потом повторить эти команды, есть минусы, например первая загрузка объекта будет медленнее, чем следующие.

Хотелось бы услышать мнение, кто уже сталкивался с подобной задачей.
Re[3]: Загрузка и выполнение DynamicMethod из byte массива
От: Sinclair Россия https://github.com/evilguest/
Дата: 17.07.13 10:12
Оценка:
Здравствуйте, qlat, Вы писали:

Q>не соглашусь,

Q>повторный запуск программы и использование в ней DynamicMethod уже не является одноразовым использованием
И? Если у вас при повторном запуске программы генерируется один и тот же код, то в чём смысл делать его динамическим? Почему просто не поместить его во вполне статическую сборку?

Q>DynamicMethod мне подходит, достаточно просто сохранить в свой формат все что я создаю в нем на уровне reflection.emit, а потом повторить эти команды, есть минусы, например первая загрузка объекта будет медленнее, чем следующие.

Пока что видно, что dynamic method вам категорически не подходит, т.к. в нём нет методов, которые вам нужны.
Почему вы думаете, что в стриме ILGenerator содержится всё, что нужно?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[4]: Загрузка и выполнение DynamicMethod из byte массива
От: qlat  
Дата: 17.07.13 12:19
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, qlat, Вы писали:


Q>>не соглашусь,

Q>>повторный запуск программы и использование в ней DynamicMethod уже не является одноразовым использованием
S>И? Если у вас при повторном запуске программы генерируется один и тот же код, то в чём смысл делать его динамическим? Почему просто не поместить его во вполне статическую сборку?

Вы писали свою среду для программирования, как в 1С, Navision, Axapta, SAP и т.д.?
Если да, прошу поделиться опытом.
Re[5]: Загрузка и выполнение DynamicMethod из byte массива
От: Codechanger Россия  
Дата: 17.07.13 14:03
Оценка:
Здравствуйте, qlat, Вы писали:
Q>Вы писали свою среду для программирования, как в 1С, Navision, Axapta, SAP и т.д.?
Q>Если да, прошу поделиться опытом.


Ну вот и задача всплыла. Пишется среда программирования, т.е. IDE. По идее, данные должны лежать в исходниках, а компилироваться в сборки уже по запросу. Т.е. есть некий язык , на котором программа пишется и сохраняется в некоторое множество исходных файлов. Потом уже это множество преобразуется в бинарный формат для исполнения. Я вот как-то так это вижу. Ну и куча лишней головной боли сразу отпадет, ибо надо четко понимать, что данные удобно хранить и редактировать в одном виде, а исполнять — совсем в другом .
Re[6]: Загрузка и выполнение DynamicMethod из byte массива
От: qlat  
Дата: 17.07.13 16:43
Оценка:
Здравствуйте, Codechanger, Вы писали:

C>Здравствуйте, qlat, Вы писали:

Q>>Вы писали свою среду для программирования, как в 1С, Navision, Axapta, SAP и т.д.?
Q>>Если да, прошу поделиться опытом.


C>Ну вот и задача всплыла. Пишется среда программирования, т.е. IDE. По идее, данные должны лежать в исходниках, а компилироваться в сборки уже по запросу. Т.е. есть некий язык , на котором программа пишется и сохраняется в некоторое множество исходных файлов. Потом уже это множество преобразуется в бинарный формат для исполнения. Я вот как-то так это вижу. Ну и куча лишней головной боли сразу отпадет, ибо надо четко понимать, что данные удобно хранить и редактировать в одном виде, а исполнять — совсем в другом .


я хотел решить простую задачу

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