gpt4 book ai didi

c# - 如何让 ReadJson 返回 "default"行为——就好像 CanConvert 返回 false

转载 作者:太空宇宙 更新时间:2023-11-03 12:36:13 25 4
gpt4 key购买 nike

  • 我已经创建了 JsonConverter 的实现
  • CanConvert 始终返回 true。
  • ReadJson 中,我有时只想使用“默认”行为,就好像 CanConvert 返回了 false 而我的 ReadJson 从未被调用过.
  • 许多其他帖子建议我做以下一些变体:

existingValue = existingValue ?? serializer
.ContractResolver
.ResolveContract(objectType)
.DefaultCreator();
serializer.Populate(reader, existingValue);
  • 但是,这会在 .DefaultCreator() 上抛出 NullReferenceException
  • existingValue 始终为 null
  • 从序列化程序返回的 ContractResolver 是我自己的。它扩展了 json.net 的内置 CamelCasePropertyNamesContractResolver 并简单地覆盖了方法 CreateConstructorParametersCreatePropertyFromConstructorParameter

我如何告诉 json.net -“开个玩笑,我不知道如何创建这个东西,如果我告诉你我无法创建它,你会做任何事情来创建它”

请注意,我已经简化了讨论的问题。我预计有人会回答“只是让 CanCreate 返回 false”事实上,在许多情况下我可以而且应该创建对象。

最佳答案

从您的问题和评论来看,听起来您在某些情况下希望转换器读取但不写入,而在其他情况下您希望它写入但不读取。通过将功能拆分为两个转换器,然后让每个转换器的 CanConvert 方法在适当的时间返回 true 或 false,您已经解决了这个问题。这当然是一种可行的方法,并且似乎对您有用,这很棒。但是,我想提供一个替代解决方案。

除了 CanConvert 方法之外,基础 JsonConverter 还提供了两个您可以覆盖的虚拟 bool 属性:CanReadCanWrite 。 (默认情况下均返回 true。)这些属性直接控制 ReadJsonWriteJson 是否由特定转换器的序列化程序调用。因此,例如,如果 CanRead 返回 false,则 ReadJson 将不会被调用,而是使用默认读取行为,即使 CanConvert返回真。这使您可以非常巧妙地设置非对称转换器。例如,您可能会遇到这样一种情况,您希望将疯狂的 JSON 格式反序列化为更合理的对象结构,但是当您再次对其进行序列化时,您不想回到疯狂的 JSON 格式——您只想要默认序列化。在这种情况下,您将覆盖转换器中的 CanWrite 以始终返回 false。然后你可以将 WriteJson 的实现留空或者让它抛出一个 NotImplementedException;它永远不会被调用。

您的案例听起来比这复杂一点,但您仍然应该能够操纵 CanReadCanWrite 属性来实现您想要的结果。下面是一个人为设计的示例,展示了我们如何根据情境变量打开和关闭 ReadJsonWriteJson 方法。

public class Program
{
public static void Main(string[] args)
{
string json = @"{""keys"":[""foo"",""fizz""],""values"":[""bar"",""bang""]}";

CustomConverter converter = new CustomConverter();
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Converters.Add(converter);

// Here we are reading a JSON object containing two arrays into a dictionary
// (custom read) and then writing out the dictionary JSON (standard write)
Console.WriteLine("--- Situation 1 (custom read, standard write) ---");
converter.Behavior = ConverterBehavior.CustomReadStandardWrite;
json = DeserializeThenSerialize(json, settings);

// Here we are reading a simple JSON object into a dictionary (standard read)
// and then writing out a new JSON object containing arrays (custom write)
Console.WriteLine("--- Situation 2 (standard read, custom write) ---");
converter.Behavior = ConverterBehavior.StandardReadCustomWrite;
json = DeserializeThenSerialize(json, settings);
}

private static string DeserializeThenSerialize(string json, JsonSerializerSettings settings)
{
Console.WriteLine("Deserializing...");
Console.WriteLine(json);
var dict = JsonConvert.DeserializeObject<Dictionary<string, string>>(json, settings);
foreach (var kvp in dict)
{
Console.WriteLine(kvp.Key + ": " + kvp.Value);
}

Console.WriteLine("Serializing...");
json = JsonConvert.SerializeObject(dict, settings);
Console.WriteLine(json);
Console.WriteLine();

return json;
}
}

enum ConverterBehavior { CustomReadStandardWrite, StandardReadCustomWrite }

class CustomConverter : JsonConverter
{
public ConverterBehavior Behavior { get; set; }

public override bool CanConvert(Type objectType)
{
return typeof(IDictionary<string, string>).IsAssignableFrom(objectType);
}

public override bool CanRead
{
get { return Behavior == ConverterBehavior.CustomReadStandardWrite; }
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
Console.WriteLine("ReadJson was called");

// Converts a JSON object containing a keys array and a values array
// into a Dictionary<string, string>
JObject jo = JObject.Load(reader);
return jo["keys"].Zip(jo["values"], (k, v) => new JProperty((string)k, v))
.ToDictionary(jp => jp.Name, jp => (string)jp.Value);
}

public override bool CanWrite
{
get { return Behavior == ConverterBehavior.StandardReadCustomWrite; }
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
Console.WriteLine("WriteJson was called");

// Converts a dictionary to a JSON object containing
// a keys array and a values array from the dictionary
var dict = (Dictionary<string, string>)value;
JObject jo = new JObject(new JProperty("keys", new JArray(dict.Keys)),
new JProperty("values", new JArray(dict.Values)));
jo.WriteTo(writer);
}
}

输出:

--- Situation 1 (custom read, standard write) ---
Deserializing...
{"keys":["foo","fizz"],"values":["bar","bang"]}
ReadJson was called
foo: bar
fizz: bang
Serializing...
{"foo":"bar","fizz":"bang"}

--- Situation 2 (standard read, custom write) ---
Deserializing...
{"foo":"bar","fizz":"bang"}
foo: bar
fizz: bang
Serializing...
WriteJson was called
{"keys":["foo","fizz"],"values":["bar","bang"]}

fiddle :https://dotnetfiddle.net/BdtSoN

关于c# - 如何让 ReadJson 返回 "default"行为——就好像 CanConvert 返回 false,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40913277/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com