Генерация объектно-ориентированного кода. Технология CodeDom
Создание цикла
Рассмотрим код, создающий цикл:
//Создание цикла
CodeVariableDeclarationStatement MyVariable = new CodeVariableDeclarationStatement(typeof(int), "i");
MyVariable.InitExpression = new CodeSnippetExpression("0");
CodeIterationStatement forLoop = new CodeIterationStatement();
forLoop.InitStatement = MyVariable;
CodeAssignStatement assignment = new CodeAssignStatement(
new CodeVariableReferenceExpression("i"),
new CodeSnippetExpression("i + 1"));
forLoop.IncrementStatement = assignment;
forLoop.TestExpression = new CodeSnippetExpression("i < MyCount");
MyGenericMethod.Statements.Add(forLoop);
Пример
6.8.
CodeIterationStatement используется для создания цикла for. CodeSnippetExpression подставляет блок текста в генерируемый код. Через свойство цикла InitStatement назначается условие инициации переменной цикла. А IncrementStatement применяется для задания условия увеличения счетчика переменной цикла. CodeAssignStatement назначает переменной новое значение. При этом CodeVariableReferenceExpression выводит имя переменной в генерируемый код. Через свойство цикла TestExpression назначается условие, при котором выполняется цикл.
Если мы сгенерируем код в таком виде, то содержимое цикла у нас будет пустым. Добавим несколько операторов в свойство Statements цикла:
CodeBinaryOperatorExpression operate = new CodeBinaryOperatorExpression(
new CodePrimitiveExpression("item "),
CodeBinaryOperatorType.Add,
new CodeVariableReferenceExpression("i"));
forLoop.Statements.Add(new CodeMethodInvokeExpression(
new CodeMethodReferenceExpression(
new CodeVariableReferenceExpression("MyList"),
"Add"),operate));
Пример
6.9.
Внутри цикла через CodeMethodReferenceExpression создается вызов метода Add. При этом в параметры передается выражение CodeBinaryOperatorExpression, представляющее собой бинарную операцию над двумя другими выражениями. Через перечисление CodeBinaryOperatorType указываем, что нам нужно сложение, то есть Add. В первой части выражения будет стоять строка "item ", а во второй части - переменная i.
Аналогично добавим вывод на консоль значения элемента списка:
CodeExpression expr = new CodeMethodInvokeExpression(
new CodeMethodReferenceExpression(
new CodeVariableReferenceExpression("System.Console"),
"WriteLine"),
new CodeArgumentReferenceExpression("MyList[i]"));
forLoop.Statements.Add(expr);
Пример
6.10.
CodeArgumentReferenceExpression служит для ссылки на выражение аргумента функции. В завершение в свойство Statements нашего метода добавим еще код для считывания клавиши:
CodeExpression readkey = new CodeMethodInvokeExpression(
new CodeMethodReferenceExpression(
new CodeVariableReferenceExpression("System.Console"),
"ReadKey"),
new CodeArgumentReferenceExpression(""));
MyGenericMethod.Statements.Add(readkey);
Пример
6.11.
Вывод результата генерации в файл
Мы рассмотрели возможности построения дерева CodeDom, однако нужно еще сгенерировать код и сохранить его. Для этого используется метод GenerateCodeFromCompileUnit провайдера:
private static void WriteGeneratedFile(CodeCompileUnit compileUnit, string lang)
{
string path = @"C:\Users\agpx\Desktop\Code Generation\Code Generation Lections\examples CodeDom\MyGenericExample";
CodeDomProvider provider;
if (lang == "C#")
{
provider = new CSharpCodeProvider();
path += ".cs";
}
else
{
provider = new VBCodeProvider();
path += ".vb";
}
using (StreamWriter sw = new StreamWriter(path, false))
{
IndentedTextWriter tw = new IndentedTextWriter(sw, " ");
provider.GenerateCodeFromCompileUnit(compileUnit, tw, new CodeGeneratorOptions());
tw.Close();
}
}
Пример
6.12.
Соберем все вместе
А теперь посмотрим на созданную нами программу, объединим все предыдущие примеры и получим следующий результат:
//Создание дерева CodeDom
CodeCompileUnit compileUnit = new CodeCompileUnit();
//Инициализация объекта пространства имен с заданием имени
CodeNamespace MyGenericNameSpace = new CodeNamespace("MyNameSpace");
compileUnit.Namespaces.Add(MyGenericNameSpace);
//Импортирование пространства имен
MyGenericNameSpace.Imports.Add(new CodeNamespaceImport("System"));
MyGenericNameSpace.Imports.Add(new CodeNamespaceImport("System.Text"));
MyGenericNameSpace.Imports.Add(new CodeNamespaceImport("System.Collections.Generic"));
//Объявление класса
CodeTypeDeclaration MyGenericClass = new CodeTypeDeclaration("MyClass");
//MyGenericClass.Attributes = MemberAttributes.Static;
//MyGenericClass.TypeAttributes = System.Reflection.TypeAttributes.NotPublic;
//MyGenericClass.IsClass = true;
MyGenericNameSpace.Types.Add(MyGenericClass);
//Создание точки входа
CodeEntryPointMethod MyGenericMethod = new CodeEntryPointMethod();
MyGenericClass.Members.Add(MyGenericMethod);
//Объявление типа List<string>
CodeTypeReference MyGenericListType = new CodeTypeReference(typeof(List<string>));
//Создание списка типа List<string> с именем MyList
CodeVariableDeclarationStatement MyGenericListVariable =
new CodeVariableDeclarationStatement(MyGenericListType,"MyList");
//Создание объекта позволяющего вызывать конструкторы
CodeObjectCreateExpression MyObjectCreateExpression =
new CodeObjectCreateExpression();
//Установка вызова конструктора
MyObjectCreateExpression.CreateType = MyGenericListType;
MyGenericListVariable.InitExpression = MyObjectCreateExpression;
MyGenericMethod.Statements.Add(MyGenericListVariable);
//Создание переменной temp с типом string
CodeVariableDeclarationStatement MyTempVariable =
new CodeVariableDeclarationStatement(typeof(System.String), "temp");
MyTempVariable.InitExpression = new CodeMethodInvokeExpression(
new CodeTypeReferenceExpression("System.Console"),
"ReadLine", new CodeArgumentReferenceExpression());
MyGenericMethod.Statements.Add(MyTempVariable);
//Создание переменной MyCount с типом int
CodeVariableDeclarationStatement MyCountVariable =
new CodeVariableDeclarationStatement(typeof(System.Int32), "MyCount");
MyCountVariable.InitExpression = new CodeMethodInvokeExpression(
new CodeTypeReferenceExpression("System.Convert"),
"ToInt32", new CodeArgumentReferenceExpression("temp"));
MyGenericMethod.Statements.Add(MyCountVariable);
//Создание цикла
CodeVariableDeclarationStatement MyVariable = new CodeVariableDeclarationStatement(typeof(int), "i");
CodeIterationStatement forLoop = new CodeIterationStatement();
MyVariable.InitExpression = new CodeSnippetExpression("0");
forLoop.InitStatement = MyVariable;
CodeAssignStatement assignment = new CodeAssignStatement(
new CodeVariableReferenceExpression("i"),
new CodeSnippetExpression("i + 1"));
forLoop.IncrementStatement = assignment;
forLoop.TestExpression = new CodeSnippetExpression("i < MyCount");
MyGenericMethod.Statements.Add(forLoop);
CodeBinaryOperatorExpression operate = new CodeBinaryOperatorExpression(
new CodePrimitiveExpression("item "),
CodeBinaryOperatorType.Add,
new CodeVariableReferenceExpression("i.ToString()"));
forLoop.Statements.Add(new CodeMethodInvokeExpression(
new CodeMethodReferenceExpression(
new CodeVariableReferenceExpression("MyList"),
"Add"),operate));
CodeExpression expr = new CodeMethodInvokeExpression(
new CodeMethodReferenceExpression(
new CodeVariableReferenceExpression("System.Console"),
"WriteLine"),
new CodeArrayIndexerExpression(
new CodeVariableReferenceExpression("MyList"),
new CodeVariableReferenceExpression("i")
));
forLoop.Statements.Add(expr);
CodeExpression readkey = new CodeMethodInvokeExpression(
new CodeMethodReferenceExpression(
new CodeVariableReferenceExpression("System.Console"),
"ReadKey"),
new CodeArgumentReferenceExpression(""));
MyGenericMethod.Statements.Add(readkey);
WriteGeneratedFile(compileUnit, "C#");
WriteGeneratedFile(compileUnit, "VB");
Пример
6.13.