簡體   English   中英

有沒有辦法讓JSON.Net使用隱式轉換而不是實際類型來序列化對象?

[英]Is there a way to get JSON.Net to serialize an object using implicit conversion instead of its actual type?

考慮這個接口和類......

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的隱式轉換,分別是stringint ,它會給我這個......

{
    "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框架的情況下進行適當的反序列化。

您可以編寫轉換器(請參閱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);
    }
}

請注意,我向您的界面添加了非泛型“value”屬性,無論實際泛型類型如何都可以獲取值,而無需使用反射:

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的參數提供。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM