JSON.Net没有为收集项调用CanConvert?

Aar*_*nLS 5 c# json.net

我有一个转换器,我只想在反序列化时使用.所以我将CanWrite设置为false,这很好,所有序列化都很好.然后,Json字符串包含一个对象图,其中有一个SantaClauseCollection,其中包含一个SantaClause项目数组和一个$ type,表示它们是具体类型的SantaClause.

然而,当它在反序列化时遇到SantaClaus的集合时,它从不调用CanConvert(我有一个断点并看到SantaClausCollection,点击F5继续,然后当遇到SantaClaus集合中的项目时应该再次达到断点,但它没有).当它到达SantaClaus项目时,它不会尝试调用CanConvert.甚至没有为该项调用CanConvert来检查我的转换器是否会处理它,而是尝试反序列化它本身,这将无法工作,因为该类没有默认构造函数,也没有带有属性名匹配约定的构造函数:

无法找到用于类型SantaClaus的构造函数.一个类应该有一个默认的构造函数,一个带参数的构造函数或一个用JsonConstructor属性标记的构造函数.

我明白为什么会出现这个错误,但问题是它表明Json.net试图反序列化该对象,而不是调用CanConvert检查并查看我的转换器是否想要处理反序列化.

为什么没有为集合中的每个项目调用CanConvert?

我的转换器:

class SantaClaus2JsonConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(SantaClaus);          
    }

    /// <summary>
    /// Deserializes a SantaClaus as a SantaClausEx which has a matching constructor that allows it to deserialize naturally.
    /// </summary>       
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        return serializer.Deserialize<SantaClausEx>(reader);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }


    public override bool CanRead
    {
        get
        {
            return true;
        }
    }

    public override bool CanWrite
    {
        get
        {
            return false;//We only need this converter when reading.
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

SantaClausEx只是继承自SantaClaus,添加一个带有重命名参数的构造函数来匹配属性:

class SantaClaus //a third party class I can't modify
{
    string Name {get;set;}
    public SantaClaus(string santaClauseName) { this.Name = santaClauseName }
}

class SantaClausEx:SantaClaus 
{
    //provide a constructor with param names matching property names
    public SantaClausEx(string name) : base(name)
}
Run Code Online (Sandbox Code Playgroud)

Json.net无法反序列化SantaClaus,但它可以反序列化SantaClauseEx.

我到处使用那个SantaClauseEx类,它工作得很好,但我想让转换器自动完成.

这就是Json对集合的看法:

SantaClausCollection: [
{
  $type: "SantaClaus, XMasClasses.NET20"
  Name: "St. Bob"
},
{
  $type: "SantaClaus, XMasClasses.NET20"
  Name: "St. Jim"
}
]
Run Code Online (Sandbox Code Playgroud)

Rud*_*dis 1

我想您已将转换器添加到Converters设置对象中的集合中。

我用转换器编写了简单的测试,该测试有效

public class SantaClausJsonTest
{
    public SantaClausJsonTest()
    {
        Settings = new JsonSerializerSettings();
        Settings.TypeNameHandling = TypeNameHandling.Objects;
        Settings.Converters.Add(new SantaClaus2JsonConverter());
    }

    private JsonSerializerSettings Settings;

    [Fact]
    public void SerializeAndDeserialize()
    {
        var collection = new []
            {
                new SantaClaus("St. Bob"),
                new SantaClaus("St. Jim"),
            };

        var serialized = JsonConvert.SerializeObject(collection, Settings);

        Console.WriteLine(serialized);
        Assert.False(string.IsNullOrEmpty(serialized));

        var deserialized = JsonConvert.DeserializeObject<SantaClaus[]>(serialized, Settings);

        Console.WriteLine(deserialized.GetType().ToString());
        Assert.NotNull(deserialized);
        Assert.True(deserialized.Any(a => a.Name == "St. Bob"));
        Assert.True(deserialized.Any(a => a.Name == "St. Jim"));
    }
}

public class SantaClaus
{
    public SantaClaus(string santaClauseName)
    {
        Name = santaClauseName;
    }

    public string Name { get; private set; }
}

public class SantaClaus2JsonConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(SantaClaus);
    }

    /// <summary>
    /// Deserializes a SantaClaus as a SantaClausEx which has a matching constructor that allows it to deserialize naturally.
    /// </summary>       
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var name = string.Empty;

        while (reader.Read())
        {
            if (reader.TokenType == JsonToken.String && reader.Path.EndsWith("Name"))
            {
                name = reader.Value as string;
            }
            if (reader.TokenType == JsonToken.EndObject)
            {
                break;
            }
        }

        return Activator.CreateInstance(objectType, name);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotSupportedException();
    }


    public override bool CanRead
    {
        get
        {
            return true;
        }
    }

    public override bool CanWrite
    {
        get
        {
            return false;//We only need this converter when reading.
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 当心。请注意 DeserializeObject&lt;SantaClaus[]&gt; 中指定类型的必要性。我发现对于顶级 JSON 对象,反序列化时无法调用转换器,除非您像在通用“DeserializeObject&lt;T&gt;”方法重载中那样显式硬编码类型。例如,如果您有一个像 `{"$type":"SantaClaus","Name":"anyname"}` 这样的 JSON 字符串,并尝试使用 DeserializeObject 对其进行反序列化,它将构造一个 SantaClause 对象,但不会通过转换器的ReadJson 方法。它只会实例化类型并分配属性。一个错误,国际海事组织。 (3认同)