为啥使用 Json.NET 序列化为 json 字符串时缺少 DriveInfo 的属性?
Posted
技术标签:
【中文标题】为啥使用 Json.NET 序列化为 json 字符串时缺少 DriveInfo 的属性?【英文标题】:Why are DriveInfo's properties missing when serializing to json string using Json.NET?为什么使用 Json.NET 序列化为 json 字符串时缺少 DriveInfo 的属性? 【发布时间】:2016-09-07 06:57:44 【问题描述】:尝试使用此代码将 DrivInfo 序列化为 Json 字符串仅返回“名称”属性:
DriveInfo dr = new DriveInfo("C");
string json = Newtonsoft.Json.JsonConvert.SerializeObject(dr);
字符串结果只有:
"_name":"C:\"
DrivInfo 是密封的,所以我无法更改任何内容。有没有办法不包装?
【问题讨论】:
为什么要序列化你无法控制的类型?如果 MS 决定更改DriveInfo
的实现怎么办?
为了在公司内部使用,我编写了一个程序来转储环境信息。所以对象被序列化然后反序列化为 xml 文件。由于 XmlSerializer 与默认构造函数的限制,我使用序列化的 json 字符串。
【参考方案1】:
你的难点在于DriveInfo
实现了ISerializable
接口用于自定义序列化,而Json.NET默认尊重这个接口,使用它来序列化和反序列化类型。由于DriveInfo
完全由驱动器的名称定义,这就是它的自定义序列化代码存储到序列化流中的全部内容。
由于您只想转储DriveInfo
的属性而不关心反序列化,您可以通过设置DefaultContractResolver.IgnoreSerializableInterface = true
来禁用ISerializable
。然而,如果你这样做,你会得到一个无限递归序列化dr.RootDirectory.Root.Root...
。要解决此问题,您可以为DirectoryInfo
创建一个JsonConverter
:
public class DirectoryInfoConverter : JsonConverter
public override bool CanConvert(Type objectType)
return objectType == typeof(DirectoryInfo);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
if (reader.TokenType == JsonToken.Null)
return null;
var token = JToken.Load(reader);
return new DirectoryInfo((string)token);
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
writer.WriteValue(value.ToString());
那么你可以这样做:
DriveInfo dr = new DriveInfo("C");
var settings = new JsonSerializerSettings
ContractResolver = new DefaultContractResolver IgnoreSerializableInterface = true ,
Converters = new [] new DirectoryInfoConverter() ,
;
var json = Newtonsoft.Json.JsonConvert.SerializeObject(dr, Formatting.Indented, settings);
但是在这一点上,序列化一个中间匿名类型可能更容易:
var json = JsonConvert.SerializeObject(
new
Name = dr.Name,
DriveType = dr.DriveType,
DriveFormat = dr.DriveFormat,
IsReady = dr.IsReady,
AvailableFreeSpace = dr.AvailableFreeSpace,
TotalFreeSpace = dr.TotalFreeSpace,
TotalSize = dr.TotalSize,
RootDirectory = dr.RootDirectory.ToString(),
VolumeLabel = dr.VolumeLabel
,
Formatting.Indented);
(当然,你不能以这种格式反序列化它。)
【讨论】:
【参考方案2】:该类包含它自己的自定义序列化,它指定只应包含_name
字段。其他属性不存储在类中。它们是由环境决定的,因此不能用反序列化的值替换。
来自source code:
private const String NameField = "_name"; // For serialization
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
// No need for an additional security check - everything is public.
info.AddValue(NameField, _name, typeof(String));
其他属性是通过实际检查DriveInfo
引用的驱动器来确定的。 TotalFreeSpace
和 TotalFreeSize
之类的属性可以随时更改,并且可能不会(可能不会)应用于可以反序列化该类的另一台计算机上。
如果您可以序列化整个事物并在其他地方反序列化,那么就有可能创建一个所有属性值都错误的类的反序列化实例,因为例如,他们实际上描述了另一台计算机上的c:
驱动器。但是该类的目的是返回有关执行代码的计算机上的驱动器的信息。
如果您想传递这些数据,那么您可以随时创建自己的类并对其进行序列化。
【讨论】:
谢谢,这解释了一切。所以包装器是我唯一的方法。以上是关于为啥使用 Json.NET 序列化为 json 字符串时缺少 DriveInfo 的属性?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Json.NET 将 XML 序列化为 JSON 对象
如何将字典的值序列化为json(使用json.net)[重复]
如何使用 NewtonSoft Json.Net 将 Json 字典反序列化为平面类