成功した。
成果物
前回まで
失敗した原因はoverride
すべきところnew
してしまっていたのが原因だった。
今回
出力結果。成功。ちゃんとnamespace
やclass
が出ている。
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)); } } }
namespace
とclass
の生成は専用クラスで名前だけ渡せば済むようになった。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
, ...。
変数やメソッドの宣言も除外。クラスメンバも同様(フィールド(変数、配列、イベント、デリゲート)、プロパティ、メソッド、コンストラクタ)
対象環境
- Raspbierry pi 3 Model B+
- Raspbian stretch 9.0 2018-11-13 ※
- bash 4.4.12(1)-release ※
- SQLite 3.29.0 ※
- C# dotnet 3.0.100 ※
$ uname -a Linux raspberrypi 4.19.42-v7+ #1218 SMP Tue May 14 00:48:17 BST 2019 armv7l GNU/Linux