【问题标题】:In C#, how do you one-way serialize the unserializable?在 C# 中,如何单向序列化不可序列化的?
【发布时间】:2012-12-19 15:23:22
【问题描述】:

通常,我需要序列化一个对象,用于记录或调试。这是一种单向序列化——我以后不需要把它弄回来,我只需要把一个对象变成一个字符串写到某个地方。

是的,是的——这就是为什么你应该总是覆盖ToString 方法。我知道这个。但我经常处理我没有写过也不能改变的对象。此外,我不想为我编写的每个类都编写和更新 ToString 方法。

XML 序列化提供了一个看似完美的解决方案——只需将该对象扁平化为 XML。但是有很多限制,特别是你不能序列化 IDictionary,你必须有一个无参数的构造函数。我可以在我的课程中解决这些问题,但是 - 再说一遍 - 我经常与其他人的课程一起工作。

那么,获得对象的综合字符串表示的解决方案是什么?我缺少什么简单的东西吗?

【问题讨论】:

  • 也许一些反射来迭代并将成员呈现为字符串?但是,这很慢,因此仅适用于性能不再重要的错误场景......

标签: c# serialization


【解决方案1】:

使用您自己的逻辑(可能还有一些反射)的扩展方法怎么样?

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)
    • 添加了对匿名类型的检查(并在输出时将其标记为“新”)

【讨论】:

  • +1:这里我最喜欢扩展方法和反射,确保只序列化公开可用的属性。不过对于大班来说可能有点混乱。
  • 显然不是对性能敏感,但它看起来更像是一种调试工具而不是生产工具,因此反射应该令人满意
  • 当然,只是把它放在那里,以防 OP 决定将它放入用于重度使用环境中大型对象的日志记录机制中。鉴于 OP 不想为“每个对象”写一个,我猜他打算“大量”使用它。
  • 你将如何处理递归?例如,如果一个属性是 List,我如何列出它的所有值?我知道我可以检查 IEnumerable,但我只是想知道你走了多远。你会在兔子洞中递归多远?
  • 请注意:IsEnumerableType 仅检查泛型枚举 (IEnumerable)。它不检查 IEnumerable。没什么大不了的,但为了完整起见......
【解决方案2】:

如果您习惯于序列化为 JSON,Json.NET 是解决此问题的好方法。

【讨论】:

    猜你喜欢
    • 2011-09-04
    • 2013-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    相关资源
    最近更新 更多