Опубликован: 28.06.2006 | Уровень: специалист | Доступ: платный | ВУЗ: Московский государственный технический университет им. Н.Э. Баумана
Лекция 10:

Динамическая генерация кода

Трансляция выражений в C#

Как уже говорилось, самым простым способом динамической генерации кода является порождение текста C#-программы и компиляция этой программы с помощью компилятора C#, доступного через библиотеку классов .NET.

В нашем примере динамическую генерацию сборки осуществляет статический метод CompileToCS, который получает транслируемое выражение в виде объекта класса Expression и возвращает объект Function:

static Function CompileToCS(Expression expr)
{
 ICodeCompiler compiler = new CSharpCodeProvider().CreateCompiler();
 CompilerParameters parameters = new CompilerParameters();

 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, который в дальнейшем может быть использован для вычисления значения функции в процессе интегрирования.

Анастасия Булинкова
Анастасия Булинкова
Рабочим названием платформы .NET было
Bogdan Drumov
Bogdan Drumov
Молдова, Республика
Azamat Nurmanbetov
Azamat Nurmanbetov
Киргизия, Bishkek