Common Intermediate Language и системное программирование в Microsoft.Net. Макаров А.В - 90 стр.

UptoLike

parameters.ReferencedAssemblies.Add(“System.dll”);
parameters.ReferencedAssemblies.Add(“Integral.exe”);
parameters.GenerateInMemory = true;
string e = expr.GenerateCS();
string code = “public class FunctionCS: Function\n”+
“{\n”+
“ public override double Eval(double x)\n”+
“ {\n”+
return “+e+”;\n”+
“ }\n”+
“}\n”;
CompilerResults compilerResults =
compiler.CompileAssemblyFromSource(parameters,code);
Assembly assembly = compilerResults.CompiledAssembly;
return assembly.CreateInstance(“FunctionCS”) as Function;
}
Классы, отвечающие за компиляцию исходного кода, относятся к
пространству имен System.CodeDom.Compiler.
Основную функциональность, необходимую нам для компиляции
сгенерированной C#-программы, обеспечивает класс CSharpCodeProvider.
Метод CreateCompiler этого класса создает экземпляр компилятора C#, к
которому можно обращаться через интерфейс ICodeCompiler.
Параметры компиляции задаются через объект класса
CompilerParameters. В нашем случае это имена сборок, импортируемых ге-
нерируемой программой: System.dll и Integral.exe. Обратите внимание,
что Integral.exe – это сборка, получаемая при компиляции рассматрива-
емого нами примера. Она импортируется по причине того, что динамиче-
ски генерируемый класс FunctionCS должен наследовать от определенного
в ней абстрактного класса Function.
Параметры компиляции и строка, содержащая текст программы, пе-
редаются методу CompileAssemblyFromSource экземпляра компилятора C#.
Метод компилирует программу и возвращает объект класса
CompilerResults, содержащий результаты компиляции. Из этого объекта
мы можем получить объект рефлексии Assembly, представляющий создан-
ную в памяти динамическую сборку. Используя данный объект, мы созда-
ем экземпляр определенного в динамической сборке класса FunctionCS,
который в дальнейшем может быть использован для вычисления значения
функции в процессе интегрирования.
Динамическая генерация кода
167
непосредственное вычисление значения выражения, метод GenerateCS
транслирует выражение в фрагмент программы на C#, а метод GenerateCIL
транслирует выражение в CIL-код.
Вопросы генерации кода будут обсуждаться в следующих разделах,
поэтому сейчас мы только приведем пример CIL-кода, генерируемого ме-
тодом GenerateCIL для дерева объектов, которые представляют выражение
”2*x*x*x+3*x*x+4*x+5”:
ldc.r8 2.0
ldarg.1
mul
ldarg.1
mul
ldarg.1
mul
ldc.r8 3.0
ldarg.1
mul
ldarg.1
mul
add
ldc.r8 4.0
ldarg.1
mul
add
ldc.r8 5.0
add
Метод GenerateCS фактически восстанавливает из дерева строковое
представление выражения и в особых комментариях не нуждается.
5.1.3. Трансляция выражений в C#
Как уже говорилось, самым простым способом динамической гене-
рации кода является порождение текста C#-программы и компиляция
этой программы с помощью компилятора C#, доступного через библиоте-
ку классов .NET.
В нашем примере динамическую генерацию сборки осуществляет
статический метод CompileToCS, который получает транслируемое выраже-
ние в виде объекта класса Expression и возвращает объект Function:
static Function CompileToCS(Expression expr)
{
ICodeCompiler compiler = new CSharpCodeProvider().CreateCompiler();
CompilerParameters parameters = new CompilerParameters();
166
CIL и системное программирование в Microsoft .NET
166                          CIL и системное программирование в Microsoft .NET   Динамическая генерация кода                                        167


непосредственное вычисление значения выражения, метод GenerateCS                       parameters.ReferencedAssemblies.Add(“System.dll”);
транслирует выражение в фрагмент программы на C#, а метод GenerateCIL                  parameters.ReferencedAssemblies.Add(“Integral.exe”);
транслирует выражение в CIL-код.                                                       parameters.GenerateInMemory = true;
     Вопросы генерации кода будут обсуждаться в следующих разделах,
поэтому сейчас мы только приведем пример CIL-кода, генерируемого ме-                    string e = expr.GenerateCS();
тодом GenerateCIL для дерева объектов, которые представляют выражение                   string code = “public class FunctionCS: Function\n”+
”2*x*x*x+3*x*x+4*x+5”:                                                                    “{\n”+
     ldc.r8   2.0                                                                         “ public override double Eval(double x)\n”+
     ldarg.1                                                                              “ {\n”+
     mul                                                                                  “     return “+e+”;\n”+
     ldarg.1                                                                              “ }\n”+
     mul                                                                                  “}\n”;
     ldarg.1
     mul                                                                               CompilerResults compilerResults =
     ldc.r8   3.0                                                                      compiler.CompileAssemblyFromSource(parameters,code);
     ldarg.1                                                                           Assembly assembly = compilerResults.CompiledAssembly;
     mul                                                                               return assembly.CreateInstance(“FunctionCS”) as Function;
     ldarg.1                                                                          }
     mul                                                                              Классы, отвечающие за компиляцию исходного кода, относятся к
     add                                                                         пространству имен System.CodeDom.Compiler.
     ldc.r8   4.0                                                                     Основную функциональность, необходимую нам для компиляции
     ldarg.1                                                                     сгенерированной C#-программы, обеспечивает класс CSharpCodeProvider.
     mul                                                                         Метод CreateCompiler этого класса создает экземпляр компилятора C#, к
     add                                                                         которому можно обращаться через интерфейс ICodeCompiler.
     ldc.r8   5.0                                                                     Параметры компиляции задаются через объект класса
     add                                                                         CompilerParameters. В нашем случае это имена сборок, импортируемых ге-
     Метод GenerateCS фактически восстанавливает из дерева строковое             нерируемой программой: System.dll и Integral.exe. Обратите внимание,
представление выражения и в особых комментариях не нуждается.                    что Integral.exe – это сборка, получаемая при компиляции рассматрива-
                                                                                 емого нами примера. Она импортируется по причине того, что динамиче-
5.1.3. Трансляция выражений в C#                                                 ски генерируемый класс FunctionCS должен наследовать от определенного
     Как уже говорилось, самым простым способом динамической гене-               в ней абстрактного класса Function.
рации кода является порождение текста C#-программы и компиляция                       Параметры компиляции и строка, содержащая текст программы, пе-
этой программы с помощью компилятора C#, доступного через библиоте-              редаются методу CompileAssemblyFromSource экземпляра компилятора C#.
ку классов .NET.                                                                 Метод компилирует программу и возвращает объект класса
     В нашем примере динамическую генерацию сборки осуществляет                  CompilerResults, содержащий результаты компиляции. Из этого объекта
статический метод CompileToCS, который получает транслируемое выраже-            мы можем получить объект рефлексии Assembly, представляющий создан-
ние в виде объекта класса Expression и возвращает объект Function:               ную в памяти динамическую сборку. Используя данный объект, мы созда-
     static Function CompileToCS(Expression expr)                                ем экземпляр определенного в динамической сборке класса FunctionCS,
     {                                                                           который в дальнейшем может быть использован для вычисления значения
       ICodeCompiler compiler = new CSharpCodeProvider().CreateCompiler();       функции в процессе интегрирования.
       CompilerParameters parameters = new CompilerParameters();