考虑此接口和类...
public interface IValueHolder{}
public class ValueHolder<TValue> : IValueHolder {
public ValueHolder(TValue value) => this.value = value;
public TValue value { get; }
public static implicit operator ValueHolder<TValue>(TValue value) => new ValueHolder<TValue>(value);
public static implicit operator TValue(ValueHolder<TValue> valueHolder) => valueHolder.value;
}
class ValueStorage : Dictionary<string, IValueHolder>{}
请注意与TValue
之间的隐式转换。
这段代码的重点是我试图存储键/值对,其中值可以是任何类型,但是没有装箱惩罚。这是可能的,因为在设置或从存储中检索值时,我总是会知道类型。 (这就是为什么我不只是使用Dictionary<string, object>
的原因。)
现在考虑此代码...
var storage = new ValueStorage();
storage["UltimateQuestion"] = new ValueHolder<string>("What do you get when you multiply six by nine?");
storage["UltimateAnswer"] = new ValueHolder<int>(42);
var jsonSerializerSettings = new JsonSerializerSettings{
TypeNameHandling = TypeNameHandling.None,
Formatting = Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore
};
var jsonString = JsonConvert.SerializeObject(storage, jsonSerializerSettings);
结果是这个...
{
"UltimateQuestion": {
"value": "What do you get when you multiply six by nine?"
},
"UltimateAnswer": {
"value": 42
}
}
我希望与TValue
和string
分别进行往返int
的隐式转换,这会给我这个...
{
"UltimateQuestion": "What do you get when you multiply six by nine?",
"UltimateAnswer": 42
}
那么我怎样才能使ValueStorage<T>
序列化和反序列化为T
?我不介意编写自定义转换器(前提是它们是通用的并且可以基于TValue
)或自定义SettingsContractResolver
子类,但是我不确定从哪里开始。
我对这个问题的思考越深,我认为这个问题实际上就越难以解决。这是因为虽然序列化很容易,但是反序列化将需要知道TValue
的类型,这些类型没有以我想要的格式存储在JSON中,因此不能反序列化。 (即使上面带有嵌套对象的原始输出也存在相同的问题。您需要类型信息才能使其以任何容量工作。)
但是,为了不让这个问题暴露,存储TValue
而不是ValueHolder<TValue>
的类型信息的转换器又如何呢?
例如
{
"UltimateQuestion": {
"$type": "[Whatever TValue is--string here]",
"value": "What do you get when you multiply six by nine?"
},
"UltimateAnswer": {
"$type": "[Whatever TValue is--int here]",
"value": 42
}
}
这样,转换器可以在反序列化期间重建ValueHolder<TValue>
实例。它不是完美的,但至少可以在不暴露ValueHolder框架的情况下允许适当的反序列化。
答案 0 :(得分:0)
您可以编写一个转换器(请参见https://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm)。
public class ValueHolderJsonConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, ((IValueHolder)value).value);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return Activator.CreateInstance(objectType, serializer.Deserialize(reader));
}
public override bool CanConvert(Type objectType)
{
return typeof(IValueHolder).IsAssignableFrom(objectType);
}
}
请不要在我的接口上添加一个非泛型的“值”属性以获取值,而与实际的泛型类型无关,而无需使用反射:
public interface IValueHolder{
object value { get; }
}
public class ValueHolder<TValue> : IValueHolder
{
// as before
object IValueHolder.value => (object)value;
}
要使用它,您需要创建一个新的JsonSerializerSettings类(或追加现有的类):
var settings = new JsonSerializerSettings {
Converters = {
new ValueHolderJsonConverter()
};
并将其作为参数提供给SerializeObject和DeserializeObject。