简体   繁体   English

在C#中,如何单向序列化不可序列化?

[英]In C#, how do you one-way serialize the unserializable?

Oftentimes, I need to serialize an object, either for logging or debugging. 通常,我需要序列化一个对象,用于记录或调试。 This is a one-way serialization -- I don't need to get it back out later, I just need to turn an object into a string to write it somewhere. 这是一个单向序列化 - 我不需要稍后将其取回,我只需要将一个对象转换为字符串以将其写入某处。

Yes, yes -- this is why you should always override the ToString method. 是的,是的 - 这就是为什么你应该总是覆盖ToString方法。 I know this. 我知道这个。 But I'm often dealing with objects I didn't write and can't change. 但我经常处理我没有写的对象,也无法改变。 Additionally, I don't want to have to write and update a ToString method for every class I write. 另外,我不想为我编写的每个类编写和更新ToString方法。

XML serialization offers a seemingly perfect solution -- just flatten that object out into XML. XML序列化提供了一个看似完美的解决方案 - 只需将该对象压缩为XML。 But there are so many limitations, specifically that you can't serialize IDictionary, and you have to have a parameterless constructor. 但是有很多限制,特别是你不能序列化IDictionary,你必须有一个无参数的构造函数。 I can get around these in my classes, but -- again -- I'm often working with other people's classes. 我可以在课堂上解决这些问题,但是 - 再次 - 我经常和其他人一起上课。

So, what's the solution to getting an comprehensive string representation of an object? 那么,获得对象的综合字符串表示的解决方案是什么? Is there something simple that I'm missing? 有什么简单的东西我错过了吗?

How about an extension method with your own logic (and maybe some Reflection)? 如何使用您自己的逻辑扩展方法(也许是一些反射)?

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;
    }
}

Call it like so: 这样称呼它:

someDefinedObject.OneWaySerialize();

Revisisons Revisisons

  1. Initial version 初始版本
  2. Updated 12.26.2012 更新于12.26.2012
    • Added check for IEnumerable (thanks aboveyou00) 添加了对IEnumerable的检查(感谢aboveyou00)
    • Added check for anonymous type (and just label it "new" when output) 添加了对匿名类型的检查(并在输出时将其标记为“new”)

如果您喜欢序列化为JSON, Json.NET是解决此问题的绝佳解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM