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

Код: 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
Сконструировать через Emit класс, реализущий заданный интерфейс
    #39899232
Фотография Antonariy
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Попытался унаследоваться от базового класса с уже реализованными свойствами, и тоже облом. Ошибок нет, но в окне контрольных значений видно, что в сконструированном классе появляются дубли базовых свойств, перекрывающие их. Соответственно, Reflection получившегося типа дергает перекрывшие, а не базовые.

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

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

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

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

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

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


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

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

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

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


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

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


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

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

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

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


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

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


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


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


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


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

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

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

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

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

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

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

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


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

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


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