【问题标题】:System.Text.Json, JsonConverter not calledSystem.Text.Json,未调用 JsonConverter
【发布时间】:2022-01-11 07:59:01
【问题描述】:

我用 .NET 6 编写了一个测试程序

        static void Main(string[] args) {
            JsonSerializerOptions options = new JsonSerializerOptions() {
                Converters = {
                    new JsonStringEnumConverter(),
                    new JsonStringAbilityEffectFactoryConverter()
                }
            };

            AbilityTemplate dictionary = JsonSerializer.Deserialize<AbilityTemplate>(@"
                {
                    ""Id"": ""StandardShot"",
                    ""Price"": 10,
                    ""Size"": 1,
                    ""Rarity"": ""Common"",
                    ""AbilityEffectFactory"": {
                        ""Id"":""StandardShotEffectFactory""
                    },
                    ""PropertyBasicValues"": {
                        ""CoolDownRate"": 5,
                        ""CastRate"": ""Infinity""
                    }
                }
            ");
        }
    }

    internal class JsonStringAbilityEffectFactoryConverter : JsonConverter<AbilityEffectFactory> {
        public override AbilityEffectFactory Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
            string id = "";//Break point here. This method is just casually implemented because I am merely especting this method to be called.
            while (reader.Read()) {
                id = reader.GetString();
            }
            return AbilityEffectFactory.Dictionary[id];
        }

        public override void Write(Utf8JsonWriter writer, AbilityEffectFactory value, JsonSerializerOptions options) {
            throw new NotImplementedException();
        }
    }

而我的 AbilityTemplate 类是这样的:

    public class AbilityTemplate : RarityObject {
        public AbilityTemplate(string id, int price, int size, Rarity rarity, AbilityEffectFactory abilityEffectFactory, in Ability.PropertyCollection propertyBasicValues) {
            Id = id;
            Price = price;
            Size = size;
            Rarity = rarity;
            AbilityEffectFactory = abilityEffectFactory;
            PropertyBasicValues = propertyBasicValues;
        }

        internal static readonly Dictionary<string, AbilityTemplate> dictionary = new Dictionary<string, AbilityTemplate>();
        public static IReadOnlyDictionary<string, AbilityTemplate> Dictionary => dictionary;
        public string Id { get; }
        public int Price { get; }
        public override Rarity Rarity { get; }
        public int Size { get; }
        public AbilityEffectFactory AbilityEffectFactory { get; }
        public Ability.PropertyCollection PropertyBasicValues { get; }
    }

父类 RarityObject 只是一个简单的抽象类,其中一个字段被覆盖:

    public abstract class RarityObject {
        public abstract Rarity Rarity { get; }
    }

但是,当代码执行时,我被抛出了异常:

System.InvalidOperationException: 'Enigma.Game.AbilityTemplate' 类型的反序列化构造函数中的每个参数都必须绑定到反序列化时的对象属性或字段。每个参数名称必须与对象上的属性或字段匹配。匹配可以不区分大小写。'

我无法理解这个异常是如何发生的。用 Json 文本编写的每个字段都已经与我的 AbilityTemplate 类的属性完全匹配。

更新0 我的 AbilityEffectFactory 是一个抽象类,也许这就是问题所在。

更新1 我将转换器修改为这样:

    internal class JsonStringAbilityTemplateConverter : JsonConverter<AbilityTemplate> {
        public override AbilityTemplate Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
            string id = "";//Break point
            while (reader.Read()) {
                id = reader.GetString();
            }
            return new AbilityTemplate();
        }

        public override void Write(Utf8JsonWriter writer, AbilityTemplate value, JsonSerializerOptions options) {
            throw new NotImplementedException();
        }
    }

但我仍然有异常:

System.NotSupportedException: '不支持没有无参数构造函数、单一参数化构造函数或带有 'JsonConstructorAttribute' 注释的参数化构造函数的类型的反序列化。键入“Enigma.Game.AbilityEffectFactory”。路径:$.AbilityEffectFactory |行号:6 | BytePositionInLine:45。'

并且没有命中断点。系统已经读取到第 6 行,这怎么可能?

【问题讨论】:

  • 如果您将所有属性的{ get; } 更改为{ get; set },是否可以解决问题?
  • @LajosArpad 但是这个类应该是不可变的
  • 解决问题了吗?我们应该知道添加一个 setter 是否会修复它,即使您没有将它应用于您的解决方案。
  • 您使用的是哪个版本的 .net-core?看起来应该可以在 .net-core 5+ docs.microsoft.com/en-us/dotnet/standard/serialization/…
  • @LajosArpad 它不起作用

标签: c# json .net system.text.json


【解决方案1】:
  1. 你的班级有错误 - Rarity 是 json 中的字符串,不能是 Rarity 班级属性

  2. 当你序列化一个对象时,你只需要属性 getter,属性 setter 可能是可选的,但是当你反序列化对象时,你需要一个 setter,至少在 Text.Json 中,因为 text json 没有正确使用构造函数。您可以尝试 Newtosoft.Json,因为它可以使用构造函数。

  3. 如果您想反序列化 json,请不要使用接口或抽象类属性,因为没有人知道要使用什么类来创建对象。一个接口或抽象类可以有数千种不同的实现

  4. 我通过用具体的字典 类替换抽象类来对您的类进行一些更改。它正在使用 Newtonsoft.Json 工作。你只需要用具体的类替换对象。

AbilityTemplate abilityTemplate = JsonConvert.DeserializeObject<AbilityTemplate>(json);

public class AbilityTemplate 
{
    [JsonConstructor]
    public AbilityTemplate(string id, int price, int size, string rarity, Dictionary<string, object> abilityEffectFactory, in Dictionary<string,object> propertyBasicValues)
    {
        Id = id;
        Price = price;
        Size = size;
        Rarity = rarity;
        AbilityEffectFactory = abilityEffectFactory;
        PropertyBasicValues = propertyBasicValues;
    }

    internal static readonly Dictionary<string, AbilityTemplate> dictionary = new Dictionary<string, AbilityTemplate>();
    public static IReadOnlyDictionary<string, AbilityTemplate> Dictionary => dictionary;
    public string Id { get; }
    public int Price { get; }
    public string Rarity { get; }
    public int Size { get; }
    public Dictionary<string,object> AbilityEffectFactory { get; }
    public Dictionary<string,object> PropertyBasicValues { get; }
}
  1. 恕我直言,您不需要特殊的转换器。如果你想把 json 转换成奇怪的东西,你可以把所有的代码放在构造函数中。

【讨论】:

    【解决方案2】:

    我终于通过不使用 JsonConverter 完成了这项工作。如下图所示,我写了可以转换为目标类的中间类。

        public static partial class EntityLoader {
            private class AbilityTemplateJsonObject {
                public string Id { get; set; }
                public int Price { get; set; }
                public int Size { get; set; }
                public string Rarity { get; set; }
                public string AbilityEffectFactory { get; set; }
                public AbilityPropertyCollectionJsonObject PropertyBasicValues { get; set; }
                public AbilityTemplate ConvertToAbilityTemplate() {
                    return new AbilityTemplate(Id, Price, Size, Enum.Parse<Rarity>(Rarity), Game.AbilityEffectFactory.Dictionary[AbilityEffectFactory], PropertyBasicValues.ConvertToAbilityPropertyCollection());
                }
            }
            private class AbilityPropertyCollectionJsonObject {
                public double Strength { get; set; }
                public double FireRate { get; set; }
                public double PerFireQuantity { get; set; }
                public double CoolDownRate { get; set; }
                public double CastRate { get; set; }
                public double Range { get; set; }
                public double ExplosionRange { get; set; }
                public double ExplosionStrength { get; set; }
                public double ManaConservation { get; set; }
                public double ManaStorage { get; set; }
                public Ability.PropertyCollection ConvertToAbilityPropertyCollection() {
                    return new Ability.PropertyCollection() {
                        [Ability.PropertyType.Strength] = Strength,
                        [Ability.PropertyType.FireRate] = FireRate,
                        [Ability.PropertyType.PerFireQuantity] = PerFireQuantity,
                        [Ability.PropertyType.CoolDownRate] = CoolDownRate,
                        [Ability.PropertyType.CastRate] = CastRate,
                        [Ability.PropertyType.Range] = Range,
                        [Ability.PropertyType.ExplosionRange] = ExplosionRange,
                        [Ability.PropertyType.ExplosionStrength] = ExplosionStrength,
                        [Ability.PropertyType.ManaConservation] = ManaConservation,
                        [Ability.PropertyType.ManaStorage] = ManaStorage
                    };
                }
            }
    
    

    【讨论】:

      猜你喜欢
      • 2020-10-05
      • 2022-12-14
      • 1970-01-01
      • 2021-08-25
      • 2020-05-01
      • 1970-01-01
      • 2014-08-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多