【问题标题】:Serializing anonymous types序列化匿名类型
【发布时间】:2017-01-17 07:19:43
【问题描述】:

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

我尝试了什么:

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, 版本=4.0.0.0,文化=中性,PublicKeyToken=b77a5c561934e089]]' 在程序集'MyProject,版本=1.0.0.0,文化=中性, PublicKeyToken=null' 未标记为可序列化。附加 信息:键入'f__AnonymousType10`2[[System.String, mscorlib,

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

【问题讨论】:

  • 你“做”错的是期望匿名类型可以用 BinaryFormatter 序列化,基本上。正如错误所说,该类型没有被标记为可序列化 - 这并不让我特别惊讶。对于支持序列化的匿名类型将是一个非常令人头疼的问题,并且无论如何都不适用于不可序列化的属性类型。
  • 您是否考虑过使用真实类型,并将其标记为可序列化?
  • 添加了匿名类型以更轻松地支持 LINQ,以避免必须为所有内容创建命名类型。它们不打算用于长期持久性、传输,甚至不用于在程序内部传递。它们旨在在本地使用。因此,匿名类型未标记为可序列化。由于二进制序列化的使用意味着您稍后想要反序列化它们,如果您告诉我们您想要在功能方面完成什么会更好,然后也许人们可以提出比“对不起,可以”更好的答案没有完成”。

标签: c# serialization anonymous


【解决方案1】:

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

[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();
}

但我无法序列化匿名类型

【讨论】:

  • 谢谢大家,将使用我的自定义类 Serializable
【解决方案2】:

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

匿名类型不履行这个角色,因为它们没有任何必需的属性。

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

【讨论】:

    【解决方案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);
            }
        }
    }
    

    【讨论】:

    • 有趣的答案,不知道你怎么知道匿名类型在没有合同的情况下应该有哪些成员,但你去吧。
    • @Jodrell 实际上,通过在使用匿名类型的两个地方设置不同的匿名类型,您很容易弄错 - 这是为什么不应该在实际代码中使用这种方法的众多原因之一。
    【解决方案4】:

    你可以,但前提是你疯了。不要使用这个。这是一个更有趣的问题。

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

    【讨论】:

      【解决方案5】:

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

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

      我正在使用动态对象来记录日志,它运行良好,因为我不需要架构。

      【讨论】:

        猜你喜欢
        • 2020-04-06
        • 2011-09-19
        • 1970-01-01
        • 2011-03-13
        • 2012-08-05
        • 2011-01-25
        • 2017-10-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多