ひきぷろのプログラミング日記

プログラミングの日記です。

(C#) コピペで使える ToStringBuilder

コピペで簡単に使える ToString ビルダーを作ってみました。
ToStringBuilder.cs で保存してください。
(Unityでも使えます。)

public なフィールドのみ表示されます。
改造するのも簡単なので、目的に合わせて書き換えてください。
"C# リフレクション" とかで検索すると、改造のしかたが分かると思います。

using System;
using System.IO;
using System.Text;

public class ToStringBuilder {
    public static string Build<T>(T t) {
        StringBuilder text = new StringBuilder();

        // 型名を表示
        Type type = Type.GetType(typeof(T).FullName);
        text.Append("(" + type.Name + ")");
        text.AppendLine(": {");

        // フィールドを巡回する
        foreach (var field in type.GetFields()) {
            // public な変数のみ
            if (field.IsPublic) {
                Type fieldType = field.FieldType;
                object fieldValue = null;

                // 配列の場合
                if (fieldType.IsArray) {
                    int index = 0;
                    fieldValue = field.GetValue(t);
                    if (fieldValue == null || (fieldValue as Array).Length <= 0) {
                        text.Append("\t");
                        text.Append(field.Name);
                        text.Append(": ");
                        text.AppendLine("null");
                    } else {
                        foreach (var value in fieldValue as Array) {
                            StringBuilder subArrayText = new StringBuilder();
                            subArrayText.Append(field.Name);
                            subArrayText.Append("[" + index + "]");
                            subArrayText.Append(" (" + value.GetType().Name + "): ");
                            subArrayText.Append(value.ToString());
                            text.Append(IndentText(subArrayText.ToString()));
                            index++;
                        }
                    }
                    continue;
                }

                // プリミティブ型、文字列型、 DateTime 型の場合
                if (fieldType.IsPrimitive
                || fieldType == typeof(string)
                || fieldType == typeof(DateTime)) {
                    text.Append("\t");
                    text.Append(field.Name);
                    text.Append(" (" + fieldType.Name + ")");
                    text.Append(": ");
                    fieldValue = field.GetValue(t);
                    if (fieldValue == null) {
                        text.AppendLine("null");
                    } else {
                        text.AppendLine(field.GetValue(t).ToString());
                    }
                    continue;
                }

                // ユーザ定義型の場合
                StringBuilder subText = new StringBuilder();
                subText.Append(field.Name);
                subText.Append(" ");
                fieldValue = field.GetValue(t);
                if (fieldValue == null) {
                    subText.AppendLine("null");
                } else {
                    subText.AppendLine(fieldValue.ToString());
                }
                text.Append(IndentText(subText.ToString()));
            }
        }

        text.Append("}");
        return text.ToString();
    }

    // 文字列の各行をインデントする
    private static string IndentText(string text, string indent = "\t") {
        StringBuilder builder = new StringBuilder();
        StringReader reader = new StringReader(text);
        string line;
        while ((line = reader.ReadLine()) != null) {
            builder.AppendLine(indent + line);
        }
        return builder.ToString();
    }
}

使い方:

// ユーザ定義型
public class UserClass {
	public string text;
	public int val;

	public override string ToString() {
		return ToStringBuilder.Build<UserClass>(this);
	}
}

表示内容 (例):

(UserClass): {
	text (String): test
	val (Int32): 123
}

ユーザ定義型の中にユーザ定義型がある場合は、そちらにも ToStringBuilder.Build() を書いてください。再帰的に表示されると思います。

十分テストできていないので、もしかすると正常に動かないケースがあるかもしれません。

追記 (2016/10/30)

null 値が入っていた場合に例外が発生することがあったので修正しました。