Json-从Json中获取反序列化对象的相应行号,以便更好地处理错误



我的应用程序接受来自客户端的长JSON模板,我对这些模板进行反序列化和处理。我想向客户提供更好的错误处理信息,其中包含JSON文本中无效对象的lineNumber。请注意,这是针对后处理中发生的错误,NOT是针对反序列化期间发生的错误。因为Newtonsoft已经处理了这一问题。

举个例子,我有下面的JSON及其相应的.Net类型

{
    "Version": "1.0.0.0",                        
    "MyComplexObject": [
    {
        "Prop1": "Val1",
        "Prop2": "Val2",
        "Prop3": 1
    }
    ]
}
public class MyComplexObject
{
    [JsonProperty]
    public string Prop1 { get; set; }
    [JsonProperty]
    public string Prop2 { get; set; }
    [JsonProperty]
    public int Prop3 { get; set; }
    **public int LineNumber;
    public int LinePosition;**
}
public class RootObject
{
    [JsonProperty]
    public string Version { get; set; }
    [JsonProperty]
    public List<MyComplexObject> MyComplexObject { get; set; }
}

我希望在反序列化时填充LineNumber和LinePosition属性,以便以后使用。我目前正在使用以下代码反序列化JSON

JsonConvert.DeserializeObject<RootObject>(value: rawJson,settings: mysettings);

感谢任何回复

我通过实现下面这样的自定义转换器来解决这个问题。任何实现JsonLineInfo的类在反序列化时都会自动获取其自身及其属性的行号信息。

public class LineInfo
{
    [JsonIgnore]
    public int LineNumber { get; set;}
    [JsonIgnore]
    public int LinePosition { get; set;}        
}
public abstract class JsonLineInfo : LineInfo
{
    [JsonIgnore]
    public Dictionary<string, LineInfo> PropertyLineInfos { get; set; }
}
class LineNumberConverter : JsonConverter
{
    public override bool CanWrite
    {
        get { return false; }
    }
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException("Converter is not writable. Method should not be invoked");
    }
    public override bool CanConvert(Type objectType)
    {
        return typeof(JsonLineInfo).IsAssignableFrom(objectType);
    }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType != JsonToken.Null)
        {
            int lineNumber = 0;
            int linePosition = 0;
            var jsonLineInfo = reader as IJsonLineInfo;
            if (jsonLineInfo != null && jsonLineInfo.HasLineInfo())
            {
                lineNumber = jsonLineInfo.LineNumber;
                linePosition = jsonLineInfo.LinePosition;
            }
            var rawJObject = JObject.Load(reader);
            var lineInfoObject = Activator.CreateInstance(objectType) as JsonLineInfo;
            serializer.Populate(this.CloneReader(reader, rawJObject), lineInfoObject);
            return this.PopulateLineInfo(
                lineInfoObject: lineInfoObject,
                lineNumber: lineNumber,
                linePosition: linePosition,
                rawJObject: rawJObject);
        }
        return null;
    }
    private JsonReader CloneReader(JsonReader reader, JObject jobject)
    {
        var clonedReader = jobject.CreateReader();
        clonedReader.Culture = reader.Culture;
        clonedReader.DateParseHandling = reader.DateParseHandling;
        clonedReader.DateTimeZoneHandling = reader.DateTimeZoneHandling;
        clonedReader.FloatParseHandling = reader.FloatParseHandling;
        clonedReader.MaxDepth = reader.MaxDepth;
        return clonedReader;
    }
    private object PopulateLineInfo(JsonLineInfo lineInfoObject, int lineNumber, int linePosition, JObject rawJObject)
    {
        if (lineInfoObject != null)
        {
            lineInfoObject.PropertyLineInfos = new Dictionary<string, LineInfo>(StringComparer.InvariantCultureIgnoreCase);
            lineInfoObject.LineNumber = lineNumber;
            lineInfoObject.LinePosition = linePosition;
            foreach (var property in rawJObject.Properties().CoalesceEnumerable())
            {
                var propertyLineInfo = property as IJsonLineInfo;
                if (propertyLineInfo != null)
                {
                    lineInfoObject.PropertyLineInfos.Add(
                        property.Name,
                        new LineInfo
                        {
                            LineNumber = propertyLineInfo.LineNumber,
                            LinePosition = propertyLineInfo.LinePosition
                        });
                }
            }
        }
        return lineInfoObject;
    }
}

以下是我在使用转换器获取数据引用时处理错误的方法:

        static string GetPosition(JsonReader reader)
        {
            if (reader is JsonTextReader textReader)
                return $"{CurrentFilename}({textReader.LineNumber},{textReader.LinePosition}):";
            else
                return $"{CurrentFilename}({reader.Path}):";
        }
        public class AudioClipConverter : JsonConverter<AudioClip>
        {
            public override void WriteJson(JsonWriter writer, AudioClip value, JsonSerializer serializer)
            {
                writer.WriteValue(value.name);
            }
            public override AudioClip ReadJson(JsonReader reader, Type objectType, AudioClip existingValue, bool hasExistingValue, JsonSerializer serializer)
            {
                var value = (string)reader.Value;
                if (String.IsNullOrEmpty(value))
                    return null;
                var result = Instance.GetAudioClip(value);
                if (result == null)
                    Debug.LogWarning($"{GetPosition(reader)} AudioClip {value} not found in database.");
                return result;
            }
        }

相关内容

  • 没有找到相关文章

最新更新