44

多くの場合、ロギングまたはデバッグのために、オブジェクトをシリアライズする必要があります。これは一方向のシリアル化です。後で戻す必要はありません。オブジェクトを文字列に変換してどこかに書き込む必要があるだけです。

はい、そうです。これが、ToStringメソッドを常にオーバーライドする必要がある理由です。私はこれを知っている。しかし、私は自分が書いたのではなく、変更できないオブジェクトを扱っていることがよくあります。さらに、作成するクラスごとに ToString メソッドを作成して更新する必要はありません。

XML シリアライゼーションは、一見完璧なソリューションを提供します。そのオブジェクトを XML にフラット化するだけです。ただし、IDictionary をシリアル化できず、パラメーターのないコンストラクターが必要になるなど、多くの制限があります。クラスでこれらを回避することはできますが、繰り返しますが、私は他の人のクラスで作業することがよくあります。

では、オブジェクトの包括的な文字列表現を取得するための解決策は何ですか? 私が見逃している簡単なものはありますか?

4

2 に答える 2

38

独自のロジック (およびおそらくいくつかのリフレクション) を持つ拡張メソッドはどうですか?

public static class SerializerExtension
{
    public static String OneWaySerialize(this Object obj)
    {
        if (Object.ReferenceEquals(obj, null))
        {
            return "NULL";
        }
        if (obj.GetType().IsPrimitive || obj.GetType() == typeof(String))
        {
            if (obj is String)
                return String.Format("\"{0}\"", obj);
            if (obj is Char)
                return String.Format("'{0}'", obj);
            return obj.ToString();
        }

        StringBuilder builder = new StringBuilder();
        Type objType = obj.GetType();
        if (IsEnumerableType(objType))
        {
            builder.Append("[");

            IEnumerator enumerator = ((IEnumerable)obj).GetEnumerator();
            Boolean moreElements = enumerator.MoveNext();
            while (moreElements)
            {
                builder.Append(enumerator.Current.OneWaySerialize());
                moreElements = enumerator.MoveNext();
                if (moreElements)
                {
                    builder.Append(",");
                }
            }

            builder.Append("]");
        }
        else
        {
            builder.AppendFormat("{0} {{ ", IsAnonymousType(objType) ? "new" : objType.Name);

            PropertyInfo[] properties = objType.GetProperties();
            for (Int32 p = properties.Length; p > 0; p--)
            {
                PropertyInfo prop = properties[p-1];
                String propName = prop.Name;
                Object propValue = prop.GetValue(obj, null);
                builder.AppendFormat("{0} = {1}", propName, propValue.OneWaySerialize());
                if (p > 1)
                {
                    builder.Append(", ");
                }
            }

            builder.Append(" }");
        }

        return builder.ToString();
    }

    // http://stackoverflow.com/a/2483054/298053
    private static Boolean IsAnonymousType(Type type)
    {
        if (type == null)
        {
            return false;
        }
        return Attribute.IsDefined(type, typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute), false)
            && type.IsGenericType && type.Name.Contains("AnonymousType")
            && (type.Name.StartsWith("<>") || type.Name.StartsWith("VB$"))
            && (type.Attributes & TypeAttributes.NotPublic) == TypeAttributes.NotPublic;
    }

    private static Boolean IsEnumerableType(Type type)
    {
        if (type == null)
        {
            return false;
        }
        foreach (Type intType in type.GetInterfaces())
        {
            if (intType.GetInterface("IEnumerable") != null || (intType.IsGenericType && intType.GetGenericTypeDefinition() == typeof(IEnumerable<>)))
            {
                return true;
            }
        }
        return false;
    }
}

次のように呼び出します。

someDefinedObject.OneWaySerialize();

改訂

  1. 初期バージョン
  2. 2012 年 12 月 26 日更新
    • IEnumerable のチェックを追加しました (aboveyou00 に感謝)
    • 匿名型のチェックを追加しました(出力時に「新しい」というラベルを付けるだけです)
于 2012-12-19T15:26:20.903 に答える
14

JSON へのシリアル化に慣れている場合は、Json.NETがこの問題の優れたソリューションになります。

于 2012-12-19T15:27:47.023 に答える