JSON.Net不调用CanConvert作为收集项目吗? [英] JSON.Net not calling CanConvert for collection item?

查看:52
本文介绍了JSON.Net不调用CanConvert作为收集项目吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个仅在反序列化时要使用的转换器.因此,我将CanWrite设置为false,这可以正常工作,并且所有Seri​​alizes都可以正常工作.然后,Json字符串包含一个对象图,其中包含一个SantaClauseCollection和一个SantaClause项数组,以及一个$ type表示它们是具体的SantaClause类型.

I have a converter that I only want used when deserializing. So I set CanWrite to false, which works fine and everything Serializes fine. The Json string then contains an object graph within which there is a SantaClauseCollection with an array of SantaClause items and a $type indicating they are concrete type SantaClause.

但是,当在反序列化时遇到SantaClaus的集合时,它永远不会调用CanConvert(我有一个断点,看到了SantaClausCollection,按F5键继续,然后在遇到该集合中的项目时应该再次达到断点,但事实并非如此).当涉及到SantaClaus项目时,它并没有尝试调用CanConvert.甚至没有为该项目调用CanConvert来检查我的转换器是否会处理它,而是尝试本身对其进行反序列化,因为该类没有默认构造函数,并且没有具有属性名称匹配约定的构造函数,所以该方法不起作用:

However, when it encounters a collection of SantaClaus while deserializing, it never calls CanConvert(I have a break point and see the SantaClausCollection, hit F5 to continue, which should then hit the break point again when encountering an item in the collection of SantaClaus, but it doesn't). It's not trying to call CanConvert when it gets to the SantaClaus item. Without even calling CanConvert for that item to check if my converter will handle it, it instead tries to deserialize it itself, which won't work because the class has no default constructor and no constructor with property-name matching conventions:

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

Unable to find a constructor to use for type SantaClaus. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute.

我理解为什么会收到此错误,但问题是Json.net尝试对对象进行反序列化,而不是调用CanConvert来检查并查看我的转换器是否要处理反序列化.

I understand why I get this error, but the problem is it indicates that Json.net tried to deserialize the object, instead of calling CanConvert to check and see if my converter wanted to handle the deserialization instead.

为什么集合中的每个项目都无法调用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.
        }
    }

}

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

SantaClausEx is just inherits from SantaClaus to add a constructor with a renamed parameter to match properties:

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)
}

Json.net不能反序列化SantaClaus,但是可以反序列化SantaClauseEx.

Json.net can't deserialize a SantaClaus, but it can deserialize a SantaClauseEx.

我在任何地方都使用该SantaClauseEx类,并且效果很好,但是我想创建一个转换器来自动执行此操作.

I use that SantaClauseEx class everywhere and it works just fine, but I wanted to make a converter to do this automatically.

这就是Json集合的外观:

This is what the Json looks like for the collection:

SantaClausCollection: [
{
  $type: "SantaClaus, XMasClasses.NET20"
  Name: "St. Bob"
},
{
  $type: "SantaClaus, XMasClasses.NET20"
  Name: "St. Jim"
}
]

推荐答案

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

I suppose that you added your converter to Converters collection in settings object.

我用可以正常工作的转换器编写了简单的测试

I wrote simple test with converter which works

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.
        }
    }

这篇关于JSON.Net不调用CanConvert作为收集项目吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆