やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

C#コードツリー構築(名前空間、クラス特化)

 成功した。

成果物

前回まで

 失敗した原因はoverrideすべきところnewしてしまっていたのが原因だった。

今回

 出力結果。成功。ちゃんとnamespaceclassが出ている。

using System;

namespace MyNamespace
{
    class MyClass
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello world");
        }
    }
}

Program.cs

using System;

namespace CodeGen
{
    class Program
    {
        static void Main(string[] args)
        {
            var gen = new CodeGenerator();
            var tree = new CodeTree()
                .Add(new CodeNode("using System;"))
                .Add(new CodeNode(""))
                .Add(new CodeNamespace("MyNamespace")
                    .Add(new CodeClass("MyClass")
                        .Add(new CodeBlock("static void Main(string[] args)")
                            .Add(new CodeNode(@"Console.WriteLine(""Hello world"");")))));
            Console.WriteLine(gen.Generate(tree));
        }
    }
}

 namespaceclassの生成は専用クラスで名前だけ渡せば済むようになった。CodeBlock("namespace ..."), "class ..."とせず。

ポイント

CodeNode.cs

class CodeNode
{
    ...
    public virtual string Generate() => Value;
}

CodeBlock.cs

class CodeBlock: CodeNode { ...

CodeNamespace.cs

class CodeNamespace: CodeBlock
{
    ...
    public override string Generate()  => $"namespace {Value}";
}

 親のGenerate()virtualにしておく。子はそれをoverrideする。

 以下で呼び出す。子CodeNamespaceを親CodeNode型として受け取る。そのインスタンスにてGenerate()呼出する。

CodeGenerator.cs

private void _Generate(CodeNode node, int indent)
{
    ...
    builder.Insert(builder.Length, Indent, indent).Append(node.Generate());
    ...

所感

 わかってしまえば簡単なことだった。

 この調子でブロック文の派生として以下を作れそう。

  • struct
  • enum

 以下は構造定義ではなく制御文なので一旦除外。

 using(){}, switch, if, for, foreach, while, try-catch-finally, ...。

 変数やメソッドの宣言も除外。クラスメンバも同様(フィールド(変数、配列、イベント、デリゲート)、プロパティ、メソッド、コンストラクタ)

対象環境

$ uname -a
Linux raspberrypi 4.19.42-v7+ #1218 SMP Tue May 14 00:48:17 BST 2019 armv7l GNU/Linux