Составители:
Рубрика:
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();
Страницы
- « первая
- ‹ предыдущая
- …
- 88
- 89
- 90
- 91
- 92
- …
- следующая ›
- последняя »
