Гость
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Сконструировать через Emit класс, реализущий заданный интерфейс / 25 сообщений из 62, страница 1 из 3
06.12.2019, 17:30
    #39899227
Antonariy
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сконструировать через Emit класс, реализущий заданный интерфейс
Нашел в тырнетах код, который класс конструирует, вот метод, создающий свойство:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
        private static void CreateProperty(this TypeBuilder tb, string propertyName, Type propertyType)
        {
            var fieldBuilder = tb.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
            var propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
            var attrs = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
            var getPropMthdBldr = tb.DefineMethod("get_" + propertyName, attrs, propertyType, Type.EmptyTypes);
            var getIl = getPropMthdBldr.GetILGenerator();

            getIl.Emit(OpCodes.Ldarg_0);
            getIl.Emit(OpCodes.Ldfld, fieldBuilder);
            getIl.Emit(OpCodes.Ret);

            var setPropMthdBldr = tb.DefineMethod("set_" + propertyName, attrs, null, new[] { propertyType });
            var setIl = setPropMthdBldr.GetILGenerator();

            setIl.MarkLabel(setIl.DefineLabel());
            setIl.Emit(OpCodes.Ldarg_0);
            setIl.Emit(OpCodes.Ldarg_1);
            setIl.Emit(OpCodes.Stfld, fieldBuilder);

            setIl.Emit(OpCodes.Nop);
            setIl.MarkLabel(setIl.DefineLabel());
            setIl.Emit(OpCodes.Ret);

            propertyBuilder.SetGetMethod(getPropMthdBldr);
            propertyBuilder.SetSetMethod(setPropMthdBldr);
        }



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

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
var tb = moduleBuilder.DefineType(typeName,
                    TypeAttributes.Public |
                    TypeAttributes.Class |
                    TypeAttributes.AutoClass |
                    TypeAttributes.AnsiClass |
                    TypeAttributes.BeforeFieldInit |
                    TypeAttributes.AutoLayout,
                    null,
                    new[] { interfaceType });


Ну и добавление свойств из интерфейса:
Код: c#
1.
2.
            foreach (var property in interfaceType.GetProperties())
                tb.CreateProperty(property.Name, property.PropertyType);

Но CreateProperty создает свойства, не связанные с интерфейсом. Экземпляр класса, созданный через Activator, без вопросов кастуется к интерфейсу, но если обратиться к экземпляру через интерфейс, то вылезает ошибка, что соответствующее свойство не реализовано.

Вопрос - как свойство класса связать со свойством интерфейса?
...
Рейтинг: 0 / 0
06.12.2019, 17:50
    #39899232
Antonariy
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сконструировать через Emit класс, реализущий заданный интерфейс
Попытался унаследоваться от базового класса с уже реализованными свойствами, и тоже облом. Ошибок нет, но в окне контрольных значений видно, что в сконструированном классе появляются дубли базовых свойств, перекрывающие их. Соответственно, Reflection получившегося типа дергает перекрывшие, а не базовые.

PS
Туплю, в источнике свойств для Emit есть одноименные записи, отсюда перекрытие.

Остался вопрос по интерфейсам.
...
Рейтинг: 0 / 0
06.12.2019, 19:01
    #39899250
buser
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сконструировать через Emit класс, реализущий заданный интерфейс
...
Рейтинг: 0 / 0
06.12.2019, 19:15
    #39899261
Antonariy
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сконструировать через Emit класс, реализущий заданный интерфейс
Слона-то я и не заметил, пытался найти подсказки в DefineProperty.
Спасибо.
...
Рейтинг: 0 / 0
06.12.2019, 21:09
    #39899294
Roman Mejtes
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сконструировать через Emit класс, реализущий заданный интерфейс
нафига такие сложности?
хотелось бы узнать, зачем вам это, не обязательно сильно детально.
не является ли это преждевременной оптимизацией или попытка сделать просто сложным? )
...
Рейтинг: 0 / 0
06.12.2019, 23:34
    #39899318
buser
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сконструировать через Emit класс, реализущий заданный интерфейс
Roman Mejtes
или попытка сделать просто сложным?
скорее - свой собственный домотканный велосипед... иногда имеет смысл...
...
Рейтинг: 0 / 0
07.12.2019, 03:01
    #39899341
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сконструировать через Emit класс, реализущий заданный интерфейс
Antonariy,

прежде чем идти в emit, я бы рекомендовал сначала решать задачу через Expression Tree, пока не упрёшься в затык по производительности.
...
Рейтинг: 0 / 0
07.12.2019, 08:47
    #39899351
Antonariy
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сконструировать через Emit класс, реализущий заданный интерфейс
Roman Mejtes
нафига такие сложности?
хотелось бы узнать, зачем вам это, не обязательно сильно детально.
не является ли это преждевременной оптимизацией или попытка сделать просто сложным? )
Вывод данных в эксель. Есть два вылизанных механизма, покрывающих все кейсы внешнего вида финального результата. Источником данных служит плоская серверная модель IEnumerable<IData>, с него получаемая или определенная на клиенте. Но описать класс и реализовать IData можно не всегда, есть несколько случаев с переменным количеством полей, собираемых из нескольких таких моделей. Под них есть зоопарк велосипедов, выводящих такие данные уникальным для каждого набора способом. Я хочу избавиться от этого зоопарка, создавая динамические модели на основе того же IEnumerable<IData>, и этот подход уже дал плоды, вскрыв несколько багов как в велосипедах, так и в данных на сервере. При правильном связывании данных, например, полезли дубли записей (косяки во внешних ключах) или новые данные, которых раньше видно не было (косяки в выводе). Пара велосипедов свелась к IEnumerable<IEnumerable<IData>>, но остальным требуется труъ динамика, набор жестких табличек не катит.

Ну а "просто" уже было сделано - к записи с фиксированными полями цеплялись наборы поле-значение, но это не спасло от говнокода. Да и отлаживать это сложнее, моск лучше анализирует коллекцию записей, чем коллекцию коллекций поле-значение.

hVosttпрежде чем идти в emit, я бы рекомендовал сначала решать задачу через Expression Tree, пока не упрёшься в затык по производительности.Посмотрел ET, показалось слишком мутным и сложным. Фабрика моделей на Emit уже заработала (CreateProperty это 80% ее кода), не вижу смысла переделывать.
...
Рейтинг: 0 / 0
07.12.2019, 21:10
    #39899461
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сконструировать через Emit класс, реализущий заданный интерфейс
Antonariy,

а без генерации классов, просто обычные модели данных, типа DataTable чем не угодили?
...
Рейтинг: 0 / 0
07.12.2019, 21:12
    #39899462
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сконструировать через Emit класс, реализущий заданный интерфейс
Antonariy
Ну а "просто" уже было сделано - к записи с фиксированными полями цеплялись наборы поле-значение, но это не спасло от говнокода. Да и отлаживать это сложнее, моск лучше анализирует коллекцию записей, чем коллекцию коллекций поле-значение.


Странно. Ну ладно. Но всё равно капец как странно. Кодогенерация в рантайме нужна по сути как костыль для биндинга к существующим решениям, или для работы с embedded кодом.

Для моделей это оверхед жёсткий имх.
...
Рейтинг: 0 / 0
07.12.2019, 22:22
    #39899468
Antonariy
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сконструировать через Emit класс, реализущий заданный интерфейс
hVostt
Antonariy,

а без генерации классов, просто обычные модели данных, типа DataTable чем не угодили?
Они изначально не использовались, под них нужно изобретать новые велосипеды. Есть объект, описывающий таблицу, завязанный на IData, есть объект, выводящий описание в эксель, тоже завязанный на IData, нахрен нужно вводить новые сущности? Проще привести данные к IData, тем более, что с твоим подходом их все равно нужно приводить к DataTable. К тому же это обошлось всего в одну страницу кода фабрики и одну строчку вызова фабрики. Проще на порядок.
...
Рейтинг: 0 / 0
07.12.2019, 22:24
    #39899469
Antonariy
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сконструировать через Emit класс, реализущий заданный интерфейс
Так и есть, это костыль к существующему решению, и очень эффективный костыль.
...
Рейтинг: 0 / 0
08.12.2019, 01:06
    #39899494
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сконструировать через Emit класс, реализущий заданный интерфейс
Antonariy,

ок, понял. если это для существующей архитектура, то оправдано.
...
Рейтинг: 0 / 0
08.12.2019, 01:07
    #39899495
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сконструировать через Emit класс, реализущий заданный интерфейс
Antonariy
очень эффективный костыль


насчёт эффективности не соглашусь )
как минимум с точки зрения сопровождения и развития..
...
Рейтинг: 0 / 0
08.12.2019, 05:07
    #39899510
fkthat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сконструировать через Emit класс, реализущий заданный интерфейс
hVostt
Для моделей это оверхед жёсткий имх.

Решение может быть очень даже годное, если, скажем, надо делать что-нибудь, типа ОРМа. Допустим, нужен код, который будет работать с классами, которые мы заранее не знаем. Единственный способ работать с ними "в лоб" - это было бы через рефлекшен, что для постоянного повторного использования было бы неэффективно, и, как выход - это использовать рефлекшен только однократно, чтобы проанализировать неизвестный класс и emit-нуть код работающий с ним уже без рефлекшена. Но, деревья выражений, конечно, проще для этого - у них под капотом тот же emit, по сути, они просто добавляют поверх него более удобный API.
...
Рейтинг: 0 / 0
08.12.2019, 08:32
    #39899514
Roman Mejtes
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сконструировать через Emit класс, реализущий заданный интерфейс
fkthat,
да полно вариантов
CodeDom, ExpressionTree, Reflection, Emit
...
Рейтинг: 0 / 0
08.12.2019, 10:46
    #39899525
Antonariy
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сконструировать через Emit класс, реализущий заданный интерфейс
hVostt
Antonariy
очень эффективный костыль


насчёт эффективности не соглашусь )
как минимум с точки зрения сопровождения и развития..
Да там нечего сопровождать и развивать. Передашь фабрике модель-источник полей и типов и лямбду, возвращающую имя поля и его тип из этого источника, получаешь тип с этими полями, вот и всё, дешево и сердито.
...
Рейтинг: 0 / 0
08.12.2019, 14:41
    #39899572
ViPRos
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сконструировать через Emit класс, реализущий заданный интерфейс
Antonariy,

да фуфло все это
DataSet наше все
...
Рейтинг: 0 / 0
08.12.2019, 15:23
    #39899585
Antonariy
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сконструировать через Emit класс, реализущий заданный интерфейс
Да на здоровье)
...
Рейтинг: 0 / 0
08.12.2019, 18:49
    #39899620
Roman Mejtes
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сконструировать через Emit класс, реализущий заданный интерфейс
Antonariy,

так важна производительность? замеры делали?
может узкое место не там.
Есть же куча всяких мапперов работающих точно так же, поищите всё уже написано :)
...
Рейтинг: 0 / 0
08.12.2019, 20:21
    #39899641
Antonariy
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сконструировать через Emit класс, реализущий заданный интерфейс
Roman Mejtes
Antonariy,

так важна производительность?
нет
...
Рейтинг: 0 / 0
09.12.2019, 00:18
    #39899703
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сконструировать через Emit класс, реализущий заданный интерфейс
fkthat
Решение может быть очень даже годное, если, скажем, надо делать что-нибудь, типа ОРМа.


Так суть ОРМ-а, это фиксированные, известные на этапе компиляции модели данных.
Какой профит от заэмиченных классов, если ты тупо код не можешь написать для работы с данными, так как классов не знаешь?

Максимум пробросить в эбмбеддед какой-нибудь. Но и там отлично всё решается без генерации классов.


fkthat
Допустим, нужен код, который будет работать с классами, которые мы заранее не знаем.


Как ты напишешь код для классов, которых не знаешь? )))


fkthat
Но, деревья выражений, конечно, проще для этого - у них под капотом тот же emit, по сути, они просто добавляют поверх него более удобный API.


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

Как бы для динамических моделей данных, нужны подходящие для этого структуры. Вот как пример DataSet. Никакого рефлекшена, никакого треша. Вся модель на руках. С данными работаем обычным образом.
...
Рейтинг: 0 / 0
09.12.2019, 02:42
    #39899727
fkthat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сконструировать через Emit класс, реализущий заданный интерфейс
hVostt
Так суть ОРМ-а, это фиксированные, известные на этапе компиляции модели данных.

Да, но не на момент компиляции самого ОРМ-а.

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

Вот тут и начинается интересное. Допустим у меня есть данные в нетипизированном виде (что-нибудь, наподобие Dictionary<string, object>) и есть ссылка на объект, тип которого я не знаю, и у меня задача скопировать словарь в этот объект по принципу ключи это имена свойств, а значения это значения соответствующих свойств. Это можно очень легко сделать через reflection. Но если это надо делать черти-сколько раз, то reflection это страшный тормоз. Поэтому можно сделать хитрее - прочитать один раз через reflection нужную инфу об объекте и по этой инфе сгенерировать emit-ом код, который будет работать уже без рефлекшена.

hVostt
Деревья выражений позволяют в динамике скомпилить операции над данными, как бы очевидный профит.

Это именно то, что я выше и попытался описать.
...
Рейтинг: 0 / 0
09.12.2019, 03:00
    #39899728
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сконструировать через Emit класс, реализущий заданный интерфейс
fkthat
hVostt
Какой профит от заэмиченных классов, если ты тупо код не можешь написать для работы с данными, так как классов не знаешь?

Вот тут и начинается интересное. Допустим у меня есть данные в нетипизированном виде (что-нибудь, наподобие Dictionary<string, object>) и есть ссылка на объект, тип которого я не знаю, и у меня задача скопировать словарь в этот объект по принципу ключи это имена свойств, а значения это значения соответствующих свойств. Это можно очень легко сделать через reflection. Но если это надо делать черти-сколько раз, то reflection это страшный тормоз. Поэтому можно сделать хитрее - прочитать один раз через reflection нужную инфу об объекте и по этой инфе сгенерировать emit-ом код, который будет работать уже без рефлекшена.


Код логики генерить понятно зачем, ради производительности. И тут лучше подойдут expression tree.

Классы зачем генерить? ))
...
Рейтинг: 0 / 0
09.12.2019, 03:02
    #39899729
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сконструировать через Emit класс, реализущий заданный интерфейс
если исключить прокси, конечно же )
...
Рейтинг: 0 / 0
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Сконструировать через Emit класс, реализущий заданный интерфейс / 25 сообщений из 62, страница 1 из 3
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]