尝试使用此代码将DrivInfo序列化为Json字符串仅返回“name”属性:
DriveInfo dr = new DriveInfo("C");
string json = Newtonsoft.Json.JsonConvert.SerializeObject(dr);
字符串结果仅为:
{"_name":"C:\"}
DrivInfo是密封的,所以我无法改变任何东西。有没有办法排除包装?
答案 0 :(得分:1)
您的难点在于DriveInfo
实现了自定义序列化的ISerializable
接口,默认情况下Json.NET尊重此接口,使用它来序列化和反序列化类型。由于DriveInfo
完全由驱动器名称定义,因此它的所有自定义序列化代码都存储在序列化流中。
由于您只想转储DriveInfo
的属性而不关心反序列化,因此您可以通过设置DefaultContractResolver.IgnoreSerializableInterface = true
来停用ISerializable
。但是,如果这样做,您将获得序列化dr.RootDirectory.Root.Root...
的无限递归。要解决此问题,您可以为JsonConverter
创建DirectoryInfo
:
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);
(当然,您无法以此格式反序列化它。)
答案 1 :(得分:0)
该类包含自己的自定义序列化,指定只应包含_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:
驱动器。但是,该类的目的是返回有关执行代码的计算机上的驱动器的信息。
如果你想传递那些数据,那么你总是可以创建自己的类并将其序列化。