尝试使用此代码将DrivInfo序列化为Json字符串只返回"name"属性:
DriveInfo dr = new DriveInfo("C");
string json = Newtonsoft.Json.JsonConvert.SerializeObject(dr);
字符串结果仅为:{"_name":"C:"}
DrivInfo已密封,因此我无法更改任何内容。有没有一种方法可以做到这一点,不包括包装?
您的困难在于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);
(当然,您将无法以这种格式对其进行反序列化。)
该类包含自己的自定义序列化,该序列化指定只应包括_name
字段。其他属性不存储在类中。它们由环境决定,因此不能用反序列化的值来替换。
来自源代码:
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:
驱动器。但该类的目的是返回有关执行代码的计算机上的驱动器的信息。
如果你想传递这些数据,那么你总是可以创建自己的类并序列化它。