序列化匿名类型

时间:2016-09-09 07:51:39

标签: c# serialization anonymous

我想将匿名类型变量转换为byte [],我该怎么做?

我尝试了什么:

byte[] result;

var my = new
{
    Test = "a1",
    Value = 0
};

BinaryFormatter bf = new BinaryFormatter();

using (MemoryStream ms = new MemoryStream())
{
    bf.Serialize(ms, my); //-- ERROR

    result = ms.ToArray();
}

我有错误:

  

类型的例外   ' System.Runtime.Serialization.SerializationException'发生在   mscorlib.dll但未在用户代码中处理

     

版本= 4.0.0.0,文化=中立,   PublicKeyToken = b77a5c561934e089],[System.Int32,mscorlib,   Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089]]'   在Assembly' MyProject中,Version = 1.0.0.0,Culture = neutral,   公钥=空'没有标记为serializable.Additional   信息:键入'<> f__AnonymousType10`2 [[System.String,mscorlib,

有人能帮助我吗?我做错了什么?或者这是不可能做到的?

5 个答案:

答案 0 :(得分:3)

首先:正如其他人所指出的那样,正确的方法是为序列化创建一个合适的类

但是,实际上可以使用Json.Net序列化匿名对象。请注意,我不建议在实际项目中实际执行此操作 - 它只是一种好奇心。

此代码依赖于通过使用示例对象作为类型持有者来访问匿名对象的基础类型的偷偷摸摸的方式:

using System;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Bson;

public class Program
{
    static void Main()
    {
        var data = serializeAnonymousObject();
        deserializeAnonymousObject(data);
    }

    static byte[] serializeAnonymousObject()
    {
        // This is in a separate method to demonstrate that you can
        // serialize in one place and deserialize in another.

        var my = new
        {
            Test  = "a1",
            Value = 12345
        };

        return Serialize(my);
    }

    static void deserializeAnonymousObject(byte[] data)
    {
        // This is in a separate method to demonstrate that you can
        // serialize in one place and deserialize in another.

        var deserialized = new  // Used as a type holder
        {
            Test  = "",
            Value = 0
        };

        deserialized = Deserialize(deserialized, data);

        Console.WriteLine(deserialized.Test);
        Console.WriteLine(deserialized.Value);
    }

    public static byte[] Serialize(object obj)
    {
        using (var ms     = new MemoryStream())
        using (var writer = new BsonWriter(ms))
        {
            new JsonSerializer().Serialize(writer, obj);
            return ms.ToArray();
        }
    }

    public static T Deserialize<T>(T typeHolder, byte[] data)
    {
        using (var ms     = new MemoryStream(data))
        using (var reader = new BsonReader(ms))
        {
            return new JsonSerializer().Deserialize<T>(reader);
        }
    }
}

答案 1 :(得分:2)

使用默认序列化程序系列(XmlSerializer,BinaryFormatter,DataContractSerializer,...)序列化的类型需要标记为[Serializable],需要是公共类型,并且需要公共读写属性。

匿名类型不具备此角色,因为它们没有必需的属性。

只需创建一个类型,然后将其序列化。

答案 2 :(得分:2)

只需创建一个可序列化的类

[Serializable]
class myClass
{
    public string Test { get; set; }
    public int Value { get; set; }
}

您可以通过以下方式序列化对象:

byte[] result;
myClass my = new myClass()
{
    Test = "a1",
    Value = 0
};
BinaryFormatter bf = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream())
{
    bf.Serialize(ms, my); //NO MORE ERROR
    result = ms.ToArray();
}

但我无法序列化匿名类型

答案 3 :(得分:2)

你可以,但只有你疯了。别用这个。这是一个更有趣的问题。

class Program
    {
        static void Main(string[] args)
        {
            var obj1 = new
            {
                Test = "a1",
                SubObject = new
                {
                    Id = 1
                },
                SubArray = new[] { new { Id = 1 }, new { Id = 2 } },
                Value = 0
            };

            var my = new AnonymousSerializer(obj1);
            BinaryFormatter bf = new BinaryFormatter();

            byte[] data;
            using (MemoryStream ms = new MemoryStream())
            {
                bf.Serialize(ms, my);
                ms.Close();
                data = ms.ToArray();
            }

            using (MemoryStream ms = new MemoryStream(data))
            {
                var a = bf.Deserialize(ms) as AnonymousSerializer;

                var obj2 = a.GetValue(obj1);

                Console.WriteLine(obj1 == obj2);

            }
            Console.ReadLine();
        }

        [Serializable]
        public class AnonymousSerializer : ISerializable
        {
            private object[] properties;

            public AnonymousSerializer(object objectToSerializer)
            {
                Type type = objectToSerializer.GetType();
                properties = type.GetProperties().Select(p =>
                {
                    if (p.PropertyType.IsArray && IsAnonymousType(p.PropertyType.GetElementType()))
                    {
                        var value = p.GetValue(objectToSerializer) as IEnumerable;
                        return value.Cast<object>().Select(obj => new AnonymousSerializer(obj)).ToArray() ;
                    }else if (IsAnonymousType(p.PropertyType))
                    {
                        var value = p.GetValue(objectToSerializer);
                        return new AnonymousSerializer(value);
                    }else{
                        return p.GetValue(objectToSerializer);
                    }
                }).ToArray();
            }

            public AnonymousSerializer(SerializationInfo info, StreamingContext context)
            {
                properties = info.GetValue("properties", typeof(object[])) as object[];
            }


            public void GetObjectData(SerializationInfo info, StreamingContext context)
            {
                info.AddValue("properties", properties);
            }

            public T GetValue<T>(T prototype)
            {
                return GetValue(typeof(T));
            }

            public dynamic GetValue(Type type)
            {
                Expression<Func<object>> exp = Expression.Lambda<Func<object>>(Creator(type));
                return exp.Compile()();
            }

            private Expression Creator(Type type)
            {
                List<Expression> param = new List<Expression>();

                for (int i = 0; i < type.GetConstructors().First().GetParameters().Length; i++)
                {
                    var cParam = type.GetConstructors().First().GetParameters()[i];
                    if (cParam.ParameterType.IsArray && IsAnonymousType(cParam.ParameterType.GetElementType()))
                    {
                        var items = properties[i] as AnonymousSerializer[];
                        var itemType = cParam.ParameterType.GetElementType();
                        var data = items.Select(aser => aser.Creator(itemType)).ToArray();
                        param.Add(Expression.NewArrayInit(itemType, data));
                    }
                    else if (IsAnonymousType(cParam.ParameterType))
                    {
                        param.Add((properties[i] as AnonymousSerializer).Creator(cParam.ParameterType));
                    }
                    else
                    {
                        param.Add(Expression.Constant(properties[i]));
                    }
                }

                return Expression.New(type.GetConstructors().First(), param);
            }

            private static bool IsAnonymousType(Type type)
            {
                bool hasCompilerGeneratedAttribute = type.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Count() > 0;
                bool nameContainsAnonymousType = type.FullName.Contains("AnonymousType");
                bool isAnonymousType = hasCompilerGeneratedAttribute && nameContainsAnonymousType;

                return isAnonymousType;
            }
        }
    }
}

答案 4 :(得分:0)

与之前的答案类似,我使用的是JSON.NET hack;

public static byte[] DynamicToByteArray(object message)
    {
        string serializeObject = JsonConvert.SerializeObject(message);
        byte[] bytes = Encoding.UTF8.GetBytes(serializeObject);
        return bytes;
    }

我正在使用动态对象进行日志记录,并且它非常有效,因为我不需要架构。