Опубликован: 25.07.2012 | Доступ: свободный | Студентов: 1544 / 44 | Оценка: 4.80 / 4.60 | Длительность: 07:59:00
Лекция 7:

Генерация объектно-ориентированного кода. Технология CodeDom

< Лекция 6 || Лекция 7: 123 || Лекция 8 >

Создание цикла

Рассмотрим код, создающий цикл:

//Создание цикла
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.
< Лекция 6 || Лекция 7: 123 || Лекция 8 >
Олег Страхов
Олег Страхов
Россия
Дмитрий Кифель
Дмитрий Кифель
Казахстан, Темиртау