问题
I'd like to convert anonymous type variable to byte[], how can I do that?
What I tried:
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();
}
I've got error:
An exception of type 'System.Runtime.Serialization.SerializationException' occurred in mscorlib.dll but was not handled in user code
Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]' in Assembly 'MyProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.Additional information: Type '<>f__AnonymousType10`2[[System.String, mscorlib,
Can somebody help me? What I'm doing wrong? Or this is not possible to do?
回答1:
Firstly: the correct approach is, as others have pointed out, to create a proper class for serialization.
However, it is actually possible to serialize an anonymous object using Json.Net. Note that I do not recommend actually doing this in a real project - it's a curiosity only.
This code relies on a sneaky way of accessing the underlying type of an anonymous object by using an exemplar object as a type holder:
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);
}
}
}
回答2:
Types that are to be serialized with the default serializer family (XmlSerializer, BinaryFormatter, DataContractSerializer, ...) need to be marked [Serializable]
, need to be public types, and will require public read-write properties.
Anonymous types don't fulfill this role, because they have none of the required properties.
Just create a type that does, and serialize that instead.
回答3:
Just create a serializable class
[Serializable]
class myClass
{
public string Test { get; set; }
public int Value { get; set; }
}
And you can serialize your object the following way:
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();
}
But i'ts not possible to serialize a anonymous type
回答4:
You can but only if you are insane. Don't use this. This was more a fun problem.
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:
Similar to previous answers, I am using JSON.NET hack;
public static byte[] DynamicToByteArray(object message)
{
string serializeObject = JsonConvert.SerializeObject(message);
byte[] bytes = Encoding.UTF8.GetBytes(serializeObject);
return bytes;
}
I am using dynamic objects my logging purposes, and it works very well since I do not need schema for that.
来源:https://stackoverflow.com/questions/39406505/serializing-anonymous-types