问题
Attempting to serialize DrivInfo to a Json string with this code only return the "name" property:
DriveInfo dr = new DriveInfo("C");
string json = Newtonsoft.Json.JsonConvert.SerializeObject(dr);
The string result is only:
{"_name":"C:\"}
DrivInfo is sealed so I cannot change anything. Is there a way to do it excluding wrapping?
回答1:
The class contains its own custom serialization which specifies that only the _name
field should be included. The other properties aren't stored in the class. They're determined by the environment, so they can't be replaced with deserialized values.
From the 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));
}
Other properties are determined by actually inspecting the drive referenced by the DriveInfo
. Properties like TotalFreeSpace
and TotalFreeSize
can change from moment to moment and may not (probably don't) apply on another computer where the class could be deserialized.
If you could serialize the whole thing and deserialize it someplace else, then it would be possible to create a deserialized instance of the class where all of the property values are wrong, because, for example, they actually describe the c:
drive on another computer. But the purpose of the class is to return information about a drive on the computer where the code is executing.
If you want to pass that data around then you can always create your own class and serialize that.
回答2:
Your difficulty is that DriveInfo implements the ISerializable interface for custom serialization, and Json.NET respects this interface by default, using it to serialize and deserialize the type. And since DriveInfo
is defined entirely by the name of the drive, that's all that it's custom serialization code stores into the serialization stream.
Since you just want to dump the properties of DriveInfo
and do not care about deserialization, you can disable use of ISerializable
by setting DefaultContractResolver.IgnoreSerializableInterface = true. However, if you do this, you'll get an infinite recursion serializing dr.RootDirectory.Root.Root.... To work around this, you could create a JsonConverter
for 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());
}
}
Then you could do:
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);
But at this point, it's probably easier just to serialize an intermediate anonymous type:
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);
(Of course, you won't be able to deserialize it in this format.)
来源:https://stackoverflow.com/questions/37170011/why-are-driveinfos-properties-missing-when-serializing-to-json-string-using-jso