鉴于以下课程:
[DataContract]
public class Enumerables
{
[DataMember]
public IEnumerable<Byte> ByteMember { get; set; }
}
一个实例初始化为:
var bytes = new byte[] { ... };
var o = new Enumerables { ByteMember = bytes };
序列化产生了这个:
{"ByteMember": "<<base-64-encoded-string>>"}
但是这个字符串不能被反序列化。产生的错误是:
Newtonsoft.Json.JsonSerializationException : Error converting value
"vbMBTToz9gyZj6gZuA59rE7ryu3fCfimjVMn8R6A0277Xs9u" to
type 'System.Collections.Generic.IEnumerable`1[System.Byte]'.
Path 'ByteMember', line 1, position 8084.
----> System.ArgumentException : Could not cast or convert from
System.String to System.Collections.Generic.IEnumerable`1[System.Byte].
我没有看到byte[]
,List<byte>
或Collection<byte>
属性发生这种情况,这些属性与base-64字符串正确序列化。对于IEnumerable<T>
不是字节的任何T
,我都不会发现这种情况发生 - 例如,IEnumerable<int>
类型的属性反序列化为List<double>
,一个有效的实施。
答案 0 :(得分:1)
IEnumerable<byte>
如何序列化取决于分配给它的具体类型。如果具体类型是byte[]
,那么它将被特别序列化为base-64编码的字符串,而如果它是一些其他具体类型,如List<byte>
,它将被序列化为正常数组数字。 ICollection<byte>
和IList<byte>
也是如此。 (DEMO)
在反序列化时,Json.Net查看目标类的成员属性的类型,以确定要创建的对象类型。当成员属性是具体类型时,没问题;它创建该类型的实例并尝试从JSON填充它。如果成员类型是一个接口,那么Json.Net必须进行猜测或抛出错误。你可以说Json.Net应该足够聪明,如果成员变量是IEnumerable<byte>
并且JSON值是base-64编码的字符串,它应该将字符串转换为byte[]
。但这不是它的实施方式。实际上,仅当成员属性为byte[]
时才会触发对base-64编码字节数组的特殊处理。由于IEnumerable<byte>
没有特殊处理,因此无法将string
直接分配给IEnumerable<byte>
,从而导致错误。同样,ICollection<byte>
或IList<byte>
也是如此。
(DEMO)
如果您希望它与IEnumerable<byte>
实现byte[]
的类型相同,那么您可以像这样制作自定义JsonConveter
:
public class EnumerableByteConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(IEnumerable<byte>).IsAssignableFrom(objectType);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
byte[] bytes = ((IEnumerable<byte>)value).ToArray();
writer.WriteValue(Convert.ToBase64String(bytes));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
byte[] bytes = Convert.FromBase64String(reader.Value.ToString());
if (objectType == typeof(byte[]))
{
return bytes;
}
return new List<byte>(bytes);
}
}
要使用转换器,请创建JsonSerializerSettings
的实例,并将转换器的实例添加到Converters
集合中。然后,将设置传递给SerializerObject()
和DeserializeObject()
方法。例如:
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Converters.Add(new EnumerableByteConverter());
string json = JsonConvert.SerializeObject(obj, settings);
这是working round-trip demo。但请注意,此转换器不会(也不能)处理可能存在的每个可能的IEnumerable<byte>
。例如,它不适用于当前实施的ISet<byte>
。如果您需要支持此类或其他类型,则需要扩展ReadJson
方法来处理该问题。我把它留给你。