C# 入れ子のオブジェクトの内部構造を文字列に変換する方法 サンプルコード

このまま動作します。
コピぺ、編集して利用するためのコードの断片です。
自由に使って頂いて構いません。

例えば、以下の構造のオブジェクトを、以下のような文字列に変換できます。
オブジェクトの入れ子に対応しています。
デバッカが使えない環境で、オブジェクトの内容をログに出力して、デバック等に使用できます。

```C#:オブジェクトの構造.cs
using System.Collections.Generic;

class class_1
{
    public List<string> a;
    public int b = 0;
    public class_1 c;
}
```

```:変換した文字列
▽(汎用.Form_Test+class_1)-------------------------------
|       ▽a(System.Collections.Generic.List`1[System.String])-------------------------------
|       |       ▽_items(System.String[])-------------------------------
|       |       |
|       |       △_items(System.String[])-------------------------------
|       |       
|       |       _size(System.Int32) = 3
|       |       _version(System.Int32) = 0
|       |       _syncRoot = Nothing
|       |       a[0](System.String) = "aaa"
|       |       a[1](System.String) = "bbb"
|       |       a[2](System.String) = "ccc"
|       |
|       △a(System.Collections.Generic.List`1[System.String])-------------------------------
|       
|       b(System.Int32) = 1
|       ▽c(汎用.Form_Test+class_1)-------------------------------
|       |       ▽a(System.Collections.Generic.List`1[System.String])-------------------------------
|       |       |       ▽_items(System.String[])-------------------------------
|       |       |       |
|       |       |       △_items(System.String[])-------------------------------
|       |       |       
|       |       |       _size(System.Int32) = 3
|       |       |       _version(System.Int32) = 0
|       |       |       _syncRoot = Nothing
|       |       |       a[0](System.String) = "ddd"
|       |       |       a[1](System.String) = "eee"
|       |       |       a[2](System.String) = "fff"
|       |       |
|       |       △a(System.Collections.Generic.List`1[System.String])-------------------------------
|       |       
|       |       b(System.Int32) = 2
|       |       c = Nothing
|       |
|       △c(汎用.Form_Test+class_1)-------------------------------
|       
|
△(汎用.Form_Test+class_1)-------------------------------
```

以下コードでオブジェクトを文字列に変換できます。

```c#:呼び出しかた.cs
s = ObjectToString(o);
```
以下の共通処理を任意の場所に貼り付ければそのまま使用できます。

```C#:共通処理.cs
using System.Text;
using System.Reflection;

/// <summary>
/// 指定されたオブジェクトの内部構造の文字列表現を返却する。
/// </summary>
/// <param name="targetObject">内部構造の文字列表現を取得する対象のオブジェクト</param>
/// <returns>オブジェクトの内部構造の文字列表現</returns>
public string ObjectToString(object targetObject)
{
    var buf = new StringBuilder();
    _ObjectToString("", targetObject, buf, "");
    return buf.ToString();
}

/// <summary>
/// 指定されたオブジェクトの内部構造の文字列表現を返却する。
/// 内部呼び出し用なので、ObjectToString以外から直接呼び出さない。
/// </summary>
/// <param name="targetFieldName">解析するオブジェクトのフィールド名</param>
/// <param name="targetObject">内部構造の文字列表現を取得する対象のオブジェクト</param>
/// <param name="buf">オブジェクトの内部構造の文字列表現の出力先バッファ</param>
/// <param name="nestString">オブジェクトの入れ子構造を表現するための文字列</param>
private void _ObjectToString(string targetFieldName, object targetObject, StringBuilder buf, string nestString)
{
    try
    {
        if (nestString.Length >= 200)
        {
            throw new Exception("階層が深すぎるので解析を打ち切ります");
        }

        if (targetObject == null)
        {
            buf.AppendLine(nestString + targetFieldName + " = Nothing");
        }
        else if (targetObject.GetType() == typeof(byte) ||
            targetObject.GetType() == typeof(short) ||
            targetObject.GetType() == typeof(int) ||
            targetObject.GetType() == typeof(long) ||
            targetObject.GetType() == typeof(float) ||
            targetObject.GetType() == typeof(double) || 
            targetObject.GetType() == typeof(decimal) ||
            targetObject.GetType() == typeof(char) ||
            targetObject.GetType() == typeof(bool) ||
            targetObject.GetType() == typeof(DateTime))
        {
            buf.AppendLine(nestString + targetFieldName + "(" + targetObject.GetType().ToString() + ") = " + targetObject.ToString());
        }
        else if (targetObject.GetType() == typeof(string))
        {
            buf.AppendLine(nestString + targetFieldName + "(" + targetObject.GetType().ToString() + ") = \"" + targetObject.ToString().Replace("\r\n", "\r\n" + nestString + "    ") + "\"");
        }
        else if (targetObject.GetType().ToString().IndexOf("System.Collections.Generic.List") == 0)
        {
            // 型：List(Of ...) への対応
            // リストの内部情報はType.GetFieldsから解析する事ができないので、自前で解析する。
            buf.AppendLine(nestString + "▽" + targetFieldName + "(" + targetObject.GetType().ToString() + ")-------------------------------");
            foreach (var field in targetObject.GetType().GetFields(BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
            {
                _ObjectToString(field.Name, field.GetValue(targetObject), buf, nestString + "|       ");
            }

            var count = (int)targetObject.GetType().GetProperty("Count").GetValue(targetObject, null);
            for (var index = 0; index <= count - 1; index++)
            {
                var param = new object[] { index };
                var item = targetObject.GetType().GetProperty("Item").GetValue(targetObject, param);
                _ObjectToString(targetFieldName + "[" + index.ToString() + "]", item, buf, nestString + "|       ");
            }

            buf.AppendLine(nestString + "|");
            buf.AppendLine(nestString + "△" + targetFieldName + "(" + targetObject.GetType().ToString() + ")-------------------------------");
            buf.AppendLine(nestString);
        }
        else
        {
            buf.AppendLine(nestString + "▽" + targetFieldName + "(" + targetObject.GetType().ToString() + ")-------------------------------");
            foreach (var field in targetObject.GetType().GetFields(BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
            {
                _ObjectToString(field.Name, field.GetValue(targetObject), buf, nestString + "|       ");
            }

            buf.AppendLine(nestString + "|");
            buf.AppendLine(nestString + "△" + targetFieldName + "(" + targetObject.GetType().ToString() + ")-------------------------------");
            buf.AppendLine(nestString);
        }
    }
    catch (Exception ex)
    {
        buf.AppendLine(nestString + "▽" + "(解析中に例外発生)-------------------------------");
        buf.AppendLine(nestString + "|       " + ex.ToString());
        buf.AppendLine(nestString + "|       " + ex.Message);
        buf.AppendLine(nestString + "|       " + ex.StackTrace);
        buf.AppendLine(nestString + "|");
        buf.AppendLine(nestString + "△" + "(解析中に例外発生)-------------------------------");
    }
}
```