Динамічне створення типів
Це ще один прийом програмування в середовищі .NET, тісно пов'язаний з метаданими, і що обіцяє не менш революційні зміни в методах програмування.
Динамічне створення програмного коду
Іноді потрібно динамічно створити програмний код, наприклад клас або перерахування. Природно, що цей код зберігатиметься у певній збірці. При цьому сама динамічно створена збірка може існувати тільки в пам'яті або може бути збережена на диску як файл.
Порядок створення відповідних об'єктів програмного коду наступний:
На основі цієї збірки згенерувати модуль;
На основі цього модуля згенерувати тип (наприклад, клас);
На основі цього типу (класу) згенерувати його члени (конструктори, методи тощо);
Виконати безпосереднє створення типу.
Нижче наведено два приклади створення динамічного коду – класу та перерахування.
Динамічне створення класу
Приклад створення класу за описаною вище методикою.
// Створення імені збирання
AssemblyName an = new AssemblyName("MyAssembly");
an.Version = new Version("1.0.0.0");
ab = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Save);
// Створення модуля у складанні
ModuleBuilder mb = ab.DefineDynamicModule("MyModule", "My.dll");
// Створення типу у збиранні
TypeBuilder tb = mb.DefineType("MyClass", TypeAttributes.Public);
/ / Створення конструктора без параметрів.
ConstructorBuilder cb0 = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, null);
// Додавання коду для конструктора
ILGenerator il0 = cb0.GetILGenerator();
// Створення конструктора з параметром типу string
ConstructorBuilder cb = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, новий Type[] < typeof(string)>);
// Додавання коду для конструктора
ILGenerator il = cb.GetILGenerator();
// Безпосереднє створення типу
// Збереження типу файл
Наведений код при запуску створить на диску файл My1.dll, в якому буде клас з двома конструкторами, причому другий конструктор при виклику виводитиме рядок "Constructor".
Два пояснення за кодом:
Дуже часто при створенні типів та членів цих типів треба вказати їх атрибути (модифікатори доступу типу public і т. п.). Це ми робимо через перерахуванняTypeAttributesіMethodAttributes, яке містить відповідні значення (Public, наприклад). Кілька необхідних значень цих перерахувань можна з'єднати через побітове "або".
Метод EmitкласуILGeneratorв якості параметра приймає перерахуванняOpCodes, яке фактично містить інструкції мовоюIL- мовою, яка є аналогом для .NET звичайного асемблера. Це означає, що його інструкції не настільки очевидні для реального програмування - саме тому як приклад такихIL-інструкцій і була наведена найпростіша з них - а саме вихід із функції (OpCodes).Ret).