C# 在列表反序列化期间忽略缺少的类型

C# 在列表反序列化期间忽略缺少的类型,c#,json,serialization,json.net,C#,Json,Serialization,Json.net,使用TypeNameHandling.All反序列化列表时,如果其中一个项的类型名称空间丢失(序列化后删除),将导致解析JSON中指定的类型时出现错误。 相反,我希望忽略这些项目,将其余项目抛在脑后 Error=(sender,args)=>{args.ErrorContext.Handled=true;}inJsonSerializerSettings执行我正在查找的操作,但当然会捕获所有错误 是否有一种更干净的方法可以做到这一点,可能是通过我错过的序列化程序设置?您可以使用内部的以下属性来限

使用
TypeNameHandling.All
反序列化列表时,如果其中一个项的类型名称空间丢失(序列化后删除),将导致解析JSON中指定的类型时出现
错误。
相反,我希望忽略这些项目,将其余项目抛在脑后

Error=(sender,args)=>{args.ErrorContext.Handled=true;}
in
JsonSerializerSettings
执行我正在查找的操作,但当然会捕获所有错误


是否有一种更干净的方法可以做到这一点,可能是通过我错过的序列化程序设置?

您可以使用内部的以下属性来限制要处理和忽略的错误类型:

  • :获取导致错误的原始对象。当由于类型名称无效而无法构造列表项时,
    OriginalObject
    将作为列表本身

    使用此属性,您可以检查
    OriginalObject
    是否是某些
    T
    IList

  • 。获取引发错误事件所针对的当前对象。异常会在序列化调用堆栈中冒泡,每个级别的对象都可以尝试处理错误

    CurrentObject==ErrorContext.OriginalObject
    时,您需要在最低级别处理它

  • -获取实际引发的异常。您将只希望处理由引发的异常

现在,如何只检测和捕获那些由于类型名绑定失败而导致的异常?事实证明,当无法加载类型时,Json.NET会抛出一个
JsonSerializationException
。但是,在许多其他情况下也可能引发相同的异常,包括格式错误的JSON文件。因此,引入一个捕获和捕获来自默认JSON绑定器的异常并将其打包为特定异常类型的:

public class JsonSerializationBinder : ISerializationBinder
{
    readonly ISerializationBinder binder;

    public JsonSerializationBinder(ISerializationBinder binder)
    {
        if (binder == null)
            throw new ArgumentNullException();
        this.binder = binder;
    }

    public Type BindToType(string assemblyName, string typeName)
    {
        try
        {
            return binder.BindToType(assemblyName, typeName);
        }
        catch (Exception ex)
        {
            throw new JsonSerializationBinderException(ex.Message, ex);
        }
    }

    public void BindToName(Type serializedType, out string assemblyName, out string typeName)
    {
        binder.BindToName(serializedType, out assemblyName, out typeName);
    }
}

public class JsonSerializationBinderException : JsonSerializationException
{
    public JsonSerializationBinderException() { }

    public JsonSerializationBinderException(string message) : base(message) { }

    public JsonSerializationBinderException(string message, Exception innerException) : base(message, innerException) { }

    public JsonSerializationBinderException(SerializationInfo info, StreamingContext context) : base(info, context) { }
}
此外,在代码Json.NET的更高级别上,在另一个
JsonSerializationException
中打包了
JsonSerializationBinderException
,因此在决定是否处理异常时,有必要查看内部异常以查找必要类型的异常。以下设置不执行此任务:

var settings = new JsonSerializerSettings
{
    SerializationBinder = new JsonSerializationBinder(new DefaultSerializationBinder()),
    TypeNameHandling = TypeNameHandling.All, // Or Auto or Objects as appropriate
    Error = (sender, args) =>
    {
        if (args.CurrentObject == args.ErrorContext.OriginalObject
            && args.ErrorContext.Error.InnerExceptionsAndSelf().OfType<JsonSerializationBinderException>().Any()
            && args.ErrorContext.OriginalObject.GetType().GetInterfaces().Any(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IList<>)))
        {
            args.ErrorContext.Handled = true;
        }
    },
};
var设置=新的JsonSerializerSettings
{
SerializationBinder=新的JsonSerializationBinder(新的DefaultSerializationBinder()),
TypeNameHandling=TypeNameHandling.All、//或自动或对象(视情况而定)
错误=(发送方,参数)=>
{
如果(args.CurrentObject==args.ErrorContext.OriginalObject
&&args.ErrorContext.Error.InnerExceptionsAndSelf().OfType().Any()
&&args.ErrorContext.OriginalObject.GetType().GetInterfaces().Any(t=>t.IsGenericType&&t.GetGenericTypeDefinition()==typeof(IList)))
{
args.ErrorContext.Handled=true;
}
},
};
使用扩展方法:

public static class ExceptionExtensions
{
    public static IEnumerable<Exception> InnerExceptionsAndSelf(this Exception ex)
    {
        while (ex != null)
        {
            yield return ex;
            ex = ex.InnerException;
        }
    }
}
公共静态类例外扩展
{
公共静态IEnumerable InnerExceptionsAndSelf(此异常为ex)
{
while(ex!=null)
{
收益率;
ex=ex.InnerException;
}
}
}
演示小提琴#1

请注意,
ISerializationBinder
是在Json.NET中引入的。在早期版本中,包装器必须从中继承并在中设置

演示小提琴2