Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 反序列化数组中的项时忽略自定义JsonConverter_C#_Json_Serialization_Json.net_Deserialization - Fatal编程技术网

C# 反序列化数组中的项时忽略自定义JsonConverter

C# 反序列化数组中的项时忽略自定义JsonConverter,c#,json,serialization,json.net,deserialization,C#,Json,Serialization,Json.net,Deserialization,编辑:制作了一个更简单、更透明的示例案例 我正在尝试反序列化组件数组(属于实体)。 其中一个组件是Sprite组件,它保存纹理和动画信息。我已经为此实现了一个CustomConverter,因为原始的sprite类有点臃肿,也没有无参数构造函数(该类来自一个单独的库,所以我无法修改它) 实际用例有点复杂,但我在下面添加了一个类似的示例。我测试了代码,同样的问题也出现了。反序列化时从不使用ReadJson。但是,当序列化WriteJson时,会被称为“非常好” 这些是组件和它的自定义转换器 pu

编辑:制作了一个更简单、更透明的示例案例

我正在尝试反序列化组件数组(属于实体)。 其中一个组件是Sprite组件,它保存纹理和动画信息。我已经为此实现了一个CustomConverter,因为原始的sprite类有点臃肿,也没有无参数构造函数(该类来自一个单独的库,所以我无法修改它)

实际用例有点复杂,但我在下面添加了一个类似的示例。我测试了代码,同样的问题也出现了。反序列化时从不使用ReadJson。但是,当序列化WriteJson时,会被称为“非常好”

这些是组件和它的自定义转换器

 public class ComponentSample
{
    int entityID;
}


public class Rect
{
    public int x;
    public int y;
    public int width;
    public int height;

    public Rect( int x, int y, int width, int height )
    {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }
}

//this class would normally have a texture and a bunch of other data that is hard to serialize
//so we will use a jsonconverter to instead point to an atlas that contains the texture's path and misc data
public class SpriteSample<TEnum> : ComponentSample
{
    Dictionary<TEnum, Rect[]> animations = new Dictionary<TEnum, Rect[]>();

    public SpriteSample( TEnum animationKey, Rect[] frames )
    {
        this.animations.Add( animationKey, frames );
    }
}

public class SpriteSampleConverter : JsonConverter<SpriteSample<int>>
{
    public override SpriteSample<int> ReadJson( JsonReader reader, Type objectType, SpriteSample<int> existingValue, bool hasExistingValue, JsonSerializer serializer )
    {
        JObject jsonObj = JObject.Load( reader );

        //get texturepacker atlas
        string atlasPath = jsonObj.Value<String>( "atlasPath" );

        //some wizardy to get all the animation and load the texture and stuff
        //for simplicity sake I'll just put in some random data
        return new SpriteSample<int>( 99, new Rect[ 1 ] { new Rect( 0, 0, 16, 16 ) } );
    }

    public override void WriteJson( JsonWriter writer, SpriteSample<int> value, JsonSerializer serializer )
    {
        writer.WriteStartObject();

        writer.WritePropertyName( "$type" );
        //actually don't know how to get the type, so I just serialized the SpriteSample<int> to check
        writer.WriteValue( "JsonSample.SpriteSample`1[[System.Int32, mscorlib]], NezHoorn" );

        writer.WritePropertyName( "animationAtlas" );
        writer.WriteValue( "sampleAtlasPathGoesHere" );

        writer.WriteEndObject();
    }
}
但当我尝试反序列化列表时,它从不在SpriteSampleConverter上调用ReadJson,而是尝试按原样反序列化对象

        JsonSerializerSettings settings = new JsonSerializerSettings();
        settings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        settings.PreserveReferencesHandling = PreserveReferencesHandling.All;
        settings.TypeNameHandling = TypeNameHandling.All;
        settings.Formatting = Formatting.Indented;
        settings.MissingMemberHandling = MissingMemberHandling.Ignore;
        settings.NullValueHandling = NullValueHandling.Ignore;
        settings.DefaultValueHandling = DefaultValueHandling.Ignore;
        settings.ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor;

        settings.Converters.Add( new SpriteSampleConverter() );

        using ( StreamReader file = File.OpenText( "sample.json" ) )
        {
            //JsonConvert.PopulateObject( file.ReadToEnd(), man, settings );
            JObject componentsJson = JObject.Parse( file.ReadToEnd() );
            //ComponentList components = JsonConvert.DeserializeObject<ComponentList>( componentsJson.ToString(), settings );
            JArray array = JArray.Parse( componentsJson.GetValue( "$values" ).ToString() );
            ComponentSample[] list = JsonConvert.DeserializeObject<ComponentSample[]>( array.ToString(), settings );

            //The SpriteSampleConverter does work here!
            SpriteSample<int> deserializedSprite = JsonConvert.DeserializeObject<SpriteSample<int>>( componentsJson.GetValue( "$values" ).ElementAt(2).ToString(), settings );
        }
JsonSerializerSettings设置=新建JsonSerializerSettings();
settings.ReferenceLoopHandling=Newtonsoft.Json.ReferenceLoopHandling.Ignore;
settings.PreserveReferencesHandling=PreserveReferencesHandling.All;
settings.typenameholling=typenameholling.All;
settings.Formatting=格式化.缩进;
settings.MissingMemberHandling=MissingMemberHandling.Ignore;
settings.NullValueHandling=NullValueHandling.Ignore;
settings.DefaultValueHandling=DefaultValueHandling.Ignore;
settings.ConstructorHandling=ConstructorHandling.AllowNonPublicDefaultConstructor;
settings.converter.Add(新的SpriteSampleConverter());
使用(StreamReader file=file.OpenText(“sample.json”))
{
//JsonConvert.PopulateObject(file.ReadToEnd(),man,settings);
JObject componentsJson=JObject.Parse(file.ReadToEnd());
//ComponentList components=JsonConvert.DeserializeObject(ComponentJSON.ToString(),设置);
JArray数组=JArray.Parse(componentsJson.GetValue(“$values”).ToString();
ComponentSample[]list=JsonConvert.DeserializeObject(array.ToString(),settings);
//SpriteSampleConverter在这里工作!
SpriteSample deserializedSprite=JsonConvert.DeserializeObject(componentsJson.GetValue($values”).ElementAt(2.ToString(),设置);
}
我做了一个快速测试,看看SpriteSampleConverter是否工作,ReadJson确实在这里被调用

SpriteSample deserializedSprite=JsonConvert.DeserializeObject>(componentsJson.GetValue($values”).ElementAt(2.ToString(),设置)

这不是有效的解决方案,因为我不知道对象是否/在哪里会有精灵组件。 我猜反序列化组件[]会让序列化程序只使用default转换器吗? 知道我做错了什么吗

编辑 我刚刚尝试了一个非泛型JsonConverter,以查看是否调用了CanConvert,令人惊讶的是,在检查类型ComponentSample[]和ComponentSample时调用了它,但SpriteSample从未通过检查

public class SpriteSampleConverterTwo : JsonConverter
{
    public override bool CanConvert( Type objectType )
    {
        return objectType == typeof( SpriteSample<int> );
    }

    public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer )
    {
        JObject jsonObj = JObject.Load( reader );

        //get texturepacker atlas
        string atlasPath = jsonObj.Value<String>( "atlasPath" );

        //some wizardy to get all the animation and load the texture and stuff
        //for simplicity sake I'll just put in some random data
        return new SpriteSample<int>( 99, new Rect[ 1 ] { new Rect( 0, 0, 16, 16 ) } );
    }

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

        writer.WritePropertyName( "$type" );
        //actually don't know how to get the type, so I just serialized the SpriteSample<int> to check
        writer.WriteValue( "JsonSample.SpriteSample`1[[System.Int32, mscorlib]], NezHoorn" );

        writer.WritePropertyName( "animationAtlas" );
        writer.WriteValue( "sampleAtlasPathGoesHere" );

        writer.WriteEndObject();
    }
}
公共类SpriteSampleConverterTwo:JsonConverter
{
公共覆盖布尔CanConvert(类型objectType)
{
返回objectType==typeof(SpriteSample);
}
公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
{
JObject jsonObj=JObject.Load(读卡器);
//获取纹理贴图器atlas
字符串atlasPath=jsonObj.Value(“atlasPath”);
//获得所有动画并加载纹理和内容的一些技巧
//为了简单起见,我只需要输入一些随机数据
返回新的SpriteSample(99,new Rect[1]{new Rect(0,0,16,16)});
}
公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
{
writer.WriteStartObject();
writer.WritePropertyName($type);
//实际上我不知道如何获取类型,所以我只是序列化了SpriteSample以进行检查
WriteValue(“JsonSample.SpriteSample`1[[System.Int32,mscorlib]],NezHoorn”);
writer.WritePropertyName(“animationAtlas”);
WriteValue(“SampleAtlaspathGoesher”);
writer.WriteEndObject();
}
}
我希望我能看看json.net的源代码,但我现在遇到了一大堆麻烦
让它运行。

我查看了json.net源代码,得出结论,只有数组声明的类型才会用于检查转换器

        JsonConverter collectionItemConverter = GetConverter(contract.ItemContract, null, contract, containerProperty);

        int? previousErrorIndex = null;

        bool finished = false;
        do
        {
            try
            {
                if (reader.ReadForType(contract.ItemContract, collectionItemConverter != null))
                {
                    switch (reader.TokenType)
                    {
                        case JsonToken.EndArray:
                            finished = true;
                            break;
                        case JsonToken.Comment:
                            break;
                        default:
                            object value;

                            if (collectionItemConverter != null && collectionItemConverter.CanRead)
                            {
                                value = DeserializeConvertable(collectionItemConverter, reader, contract.CollectionItemType, null);
                            }
它不会检查每个单独数组项的类型以查找相应的转换器


因此,我需要找到一种不同于使用转换器的解决方案。

您能尝试使用简单的标准POCOs将其归结为一种解决方案吗?事实上,如果没有
Sprite
的定义,我们真的没有希望帮助您。例如,您是否尝试反序列化其中一个多态子类型应用了自定义
JsonConverter
的多态对象集合?谢谢您的建议,我将编辑示例。是的,这正是我想要做的!
public class SpriteSampleConverterTwo : JsonConverter
{
    public override bool CanConvert( Type objectType )
    {
        return objectType == typeof( SpriteSample<int> );
    }

    public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer )
    {
        JObject jsonObj = JObject.Load( reader );

        //get texturepacker atlas
        string atlasPath = jsonObj.Value<String>( "atlasPath" );

        //some wizardy to get all the animation and load the texture and stuff
        //for simplicity sake I'll just put in some random data
        return new SpriteSample<int>( 99, new Rect[ 1 ] { new Rect( 0, 0, 16, 16 ) } );
    }

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

        writer.WritePropertyName( "$type" );
        //actually don't know how to get the type, so I just serialized the SpriteSample<int> to check
        writer.WriteValue( "JsonSample.SpriteSample`1[[System.Int32, mscorlib]], NezHoorn" );

        writer.WritePropertyName( "animationAtlas" );
        writer.WriteValue( "sampleAtlasPathGoesHere" );

        writer.WriteEndObject();
    }
}
        JsonConverter collectionItemConverter = GetConverter(contract.ItemContract, null, contract, containerProperty);

        int? previousErrorIndex = null;

        bool finished = false;
        do
        {
            try
            {
                if (reader.ReadForType(contract.ItemContract, collectionItemConverter != null))
                {
                    switch (reader.TokenType)
                    {
                        case JsonToken.EndArray:
                            finished = true;
                            break;
                        case JsonToken.Comment:
                            break;
                        default:
                            object value;

                            if (collectionItemConverter != null && collectionItemConverter.CanRead)
                            {
                                value = DeserializeConvertable(collectionItemConverter, reader, contract.CollectionItemType, null);
                            }