I'm trying to deserialize an object in an extension class, and it's not working like I would expect. I've read that I can use JsonSerializerSettings to let the JSON deserializer use a private constructor. But for some reason, JsonSerializerSettings aren't working for me. Here's the JSON reader/writer I'm using:
public class FileStorageService<T> : IStorageService<T> where T : IEquatable<T>
/// <summary>
/// Writes the given object instance to a JSON file.
/// Source: https://stackoverflow.com/questions/6201529/turn-c-sharp-object-into-a-json-string-in-net-4
/// </summary>
/// <param name="filePath">The file path to write the object instance to.</param>
/// <param name="objectToWrite">The object instance to write to the file.</param>
///
/// Comment source: https://stackoverflow.com/questions/6115721/how-to-save-restore-serializable-object-to-from-file
public void WriteJSONFile(string filePath, T objectToWrite)
{
string json = JsonConvert.SerializeObject(objectToWrite);
File.WriteAllText(filePath, json);
}
/// <summary>
/// Reads an object instance from a JSON file.
/// </summary>
/// <param name="filePath">The file path to read the object instance from.</param>
/// <returns>Returns a new instance of the object read from the JSON file.</returns>
///
/// Comment source: https://stackoverflow.com/questions/6115721/how-to-save-restore-serializable-object-to-from-file
public T ReadJSONFile(string filePath)
{
if (!File.Exists(filePath))
{
FileStream fs = new FileStream(filePath, FileMode.CreateNew);
fs.Close();
}
JsonSerializerSettings settings = new JsonSerializerSettings
{
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor
};
string json = File.ReadAllText(filePath, Encoding.UTF8);
return JsonConvert.DeserializeObject<T>(json, settings);
}
}
And here's an example of a class I'm trying to read/write:
public class MyObject : IEquatable<MyObject>
{
public string myString { get; set; }
public byte[] myBytes { get; set; }
protected MyHasher hasher;
public MyObject(string first, string second)
{
this.myString = first;
hasher = new MyHasher();
this.myBytes = hasher.ComputeHash(second);
}
... (implementing IEquatable below)
}
When I run the program in Visual Studio, I get a null pointer exception:
"An unhandled exception of type 'System.ArgumentNullException' occurred in Newtonsoft.Json.dll
Additional information: String reference not set to an instance of a String."
...pointing to the hasher.ComputeHash(second)
method, with the call stack:
> this.myBytes = hasher.ComputeHash(second);
> return JsonConvert.DeserializeObject<T>(json, settings);
Debugging it, I found that JsonConvert.DeserializeObject is calling MyObject's public constructor and giving it null values (sub-question: how is this possible?), which I don't want. I want it to use the default constructor instead.
I could add the : new()
constraint to force objects to have a public parameterless constructor, but I want my extension class to be able to handle any type of object (strings, ints, etc.), not just custom objects I create.
As a final complication, note that I can't change MyObject
in any way.
How can I do this?