はじめてのCodeDOM

Reflection.Emitに続いてCodeDOMを弄ってみました。C#VB.NET両方のソースコードを吐き出すプログラムなんですが、苦労の割に報われない気が・・・(^^; これは手作業でやるものじゃないですね。

読みにくいですが、以下、ソースコードです。

using System;
using System.IO;
using System.CodeDom;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using Microsoft.VisualBasic;

class MyApp {
  [STAThread]
  static void Main(string args) {
    CodeCompileUnit unit = new CodeCompileUnit();
    // 名前空間
    CodeNamespace ns = new CodeNamespace("MyNamespace");
    ns.Imports.Add(new CodeNamespaceImport("System"));
    // クラス
    CodeTypeDeclaration type = new CodeTypeDeclaration("MyApp");
    // Fibメソッド
    CodeMemberMethod method = new CodeMemberMethod();
    method.Name = "Fib";
    method.Attributes = MemberAttributes.Static;
    method.ReturnType = new CodeTypeReference(typeof(void));
    method.Parameters.Add(
      new CodeParameterDeclarationExpression(typeof(int), "num"));
    // 変数宣言
    method.Statements.Add(
      new CodeVariableDeclarationStatement(typeof(int), "a"));
    method.Statements.Add(
      new CodeVariableDeclarationStatement(typeof(int), "b"));
    method.Statements.Add(
      new CodeVariableDeclarationStatement(typeof(int), "t"));
    method.Statements.Add(
      new CodeVariableDeclarationStatement(typeof(int), "i"));
    // 初期化
    method.Statements.Add(new CodeAssignStatement(
      new CodeVariableReferenceExpression("a"), 
      new CodePrimitiveExpression(0)));
    method.Statements.Add(new CodeAssignStatement(
      new CodeVariableReferenceExpression("b"), 
      new CodePrimitiveExpression(1)));
    // ループ
    method.Statements.Add(new CodeIterationStatement(
      // 初期値
      new CodeAssignStatement(
      new CodeVariableReferenceExpression("i"), 
      new CodePrimitiveExpression(0)),
      // 継続条件
      new CodeBinaryOperatorExpression(
      new CodeVariableReferenceExpression("i"),
      CodeBinaryOperatorType.LessThan,
      new CodeVariableReferenceExpression("num")),
      // 次へ
      new CodeAssignStatement(
      new CodeVariableReferenceExpression("i"), 
      new CodeBinaryOperatorExpression(
      new CodeVariableReferenceExpression("i"), 
      CodeBinaryOperatorType.Add, 
      new CodePrimitiveExpression(1))),
      // ループ内処理
      new CodeStatement {
      new CodeExpressionStatement(new CodeMethodInvokeExpression( 
      new CodeTypeReferenceExpression("Console"),"WriteLine",  
      new CodeExpression { new CodeVariableReferenceExpression("b")})),
                  new CodeAssignStatement(
                  new CodeVariableReferenceExpression("t"), 
                  new CodeVariableReferenceExpression("a")),
                  new CodeAssignStatement(
                  new CodeVariableReferenceExpression("a"), 
                  new CodeVariableReferenceExpression("b")),
                  new CodeAssignStatement(
                  new CodeVariableReferenceExpression("b"),
                  new CodeBinaryOperatorExpression(
                  new CodeVariableReferenceExpression("b"),
                  CodeBinaryOperatorType.Add,
                  new CodeVariableReferenceExpression("t")))}));
    // Mainメソッド
    CodeMemberMethod main = new CodeMemberMethod();
    main.Name = "Main";
    main.ReturnType = new CodeTypeReference(typeof(void));
    main.Attributes = MemberAttributes.Static;
    main.Comments.Add(new CodeCommentStatement("CodeDomサンプル"));
    main.Statements.Add(new CodeExpressionStatement(
      new CodeMethodInvokeExpression(
      new CodeTypeReferenceExpression(type.Name), 
      method.Name, new CodeExpression {new CodePrimitiveExpression(20)})));

    type.Members.Add(method);
    type.Members.Add(main);
    ns.Types.Add(type);
    unit.Namespaces.Add(ns);

    CodeGeneratorOptions opt = new CodeGeneratorOptions();
    opt.ElseOnClosing = true;
    opt.BlankLinesBetweenMembers = true;

    // C#ソースファイル生成
    using (StreamWriter sw = new StreamWriter("fib.cs")) {
      new CSharpCodeProvider().CreateGenerator()
        .GenerateCodeFromCompileUnit(unit, sw, opt);
    }
    // VB.NETソースファイル生成
    using (StreamWriter sw = new StreamWriter("fib.vb")) {
      new VBCodeProvider().CreateGenerator()
        .GenerateCodeFromCompileUnit(unit, sw, opt);
    }
  }
}

生成されたC#ソースファイル(fib.cs)

namespace MyNamespace {
    using System;
    
    
    public class MyApp {
        
        static void Fib(int num) {
            int a;
            int b;
            int t;
            int i;
            a = 0;
            b = 1;
            for (i = 0; (i < num); i = (i + 1)) {
                Console.WriteLine(b);
                t = a;
                a = b;
                b = (b + t);
            }
        }
        
        // CodeDomサンプル
        static void Main() {
            MyApp.Fib(20);
        }
    }
}

生成されたVB.NETソースファイル(fib.vb)

Option Strict Off
Option Explicit On

Imports System

Namespace MyNamespace
    
    Public Class MyApp
        
        Shared Sub Fib(ByVal num As Integer)
            Dim a As Integer
            Dim b As Integer
            Dim t As Integer
            Dim i As Integer
            a = 0
            b = 1
            i = 0
            Do While (i < num)
                Console.WriteLine(b)
                t = a
                a = b
                b = (b + t)
                i = (i + 1)
            Loop
        End Sub
        
        'CodeDomサンプル
        Shared Sub Main()
            MyApp.Fib(20)
        End Sub
    End Class
End Namespace