取消JSON.NET流反序列化



我目前正在使用类似的代码来反序列化流中的数据。

    public static MyClass Parse(Stream stream)
    {
        var serializer = new JsonSerializer();
        using (var sr = new StreamReader(stream))
        using (var jsonTextReader = new JsonTextReader(sr))
        {
            var result = serializer.Deserialize<MyClass>(jsonTextReader);
            return result;
        }
    }

是否可以支持用户取消已启动的反序列化,因为这个过程可能需要很长时间才能处理巨大的json文件和缓慢的连接?

JsonTextReader不支持开箱即用,但Json.NET确实正确地处理了来自较低级别代码的异常(即rethrow),因此您可以对读取器进行子类化并自己执行:

public class CancellableJsonTextReader : JsonTextReader
{
    protected Func<bool> CheckCancelled { get; set; }
    public CancellableJsonTextReader(TextReader reader, Func<bool> checkCancelled)
        : base(reader)
    {
        this.CheckCancelled = checkCancelled;
    }
    public bool IsCancelled { get; private set; }
    public override bool Read()
    {
        DoCheckCancelled();
        return base.Read();
    }
    public override bool? ReadAsBoolean()
    {
        DoCheckCancelled();
        return base.ReadAsBoolean();
    }
    public override byte[] ReadAsBytes()
    {
        DoCheckCancelled();
        return base.ReadAsBytes();
    }
    public override DateTime? ReadAsDateTime()
    {
        DoCheckCancelled();
        return base.ReadAsDateTime();
    }
    public override DateTimeOffset? ReadAsDateTimeOffset()
    {
        DoCheckCancelled();
        return base.ReadAsDateTimeOffset();
    }
    public override decimal? ReadAsDecimal()
    {
        DoCheckCancelled();
        return base.ReadAsDecimal();
    }
    public override double? ReadAsDouble()
    {
        DoCheckCancelled();
        return base.ReadAsDouble();
    }
    public override int? ReadAsInt32()
    {
        DoCheckCancelled();
        return base.ReadAsInt32();
    }
    public override string ReadAsString()
    {
        DoCheckCancelled();
        return base.ReadAsString();
    }
    private void DoCheckCancelled()
    {
        if (!IsCancelled && CheckCancelled != null)
            IsCancelled = CheckCancelled();
        if (IsCancelled)
        {
            throw new JsonReaderCancelledException();
        }
    }
}
public class JsonReaderCancelledException : JsonReaderException
{
    public JsonReaderCancelledException() { }
    public JsonReaderCancelledException(string message)
        : base(message)
    {
    }
    public JsonReaderCancelledException(string message, Exception innerException)
        : base(message, innerException)
    {
    }
    public JsonReaderCancelledException(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {
    }
}

然后像这样使用:

    public static T Parse<T>(Stream stream, Func<bool> checkCancelled)
    {
        var serializer = new JsonSerializer();
        using (var sr = new StreamReader(stream))
        using (var jsonTextReader = new CancellableJsonTextReader(sr, checkCancelled))
        {
            var result = serializer.Deserialize<T>(jsonTextReader);
            return result;
        }
    }

然后,在更高的代码级别上,捕获JsonReaderCancelledException异常。

请注意,如果您的checkCancelled方法正在检查可能在另一个线程中设置的bool标志,则必须将其声明为volatile。请参阅使用布尔标志来阻止线程在C#中运行是否安全。

你我想在把它投入生产之前测试一下性能。如果每次读取都调用checkCancelled委托是不具有性能的,则可以每10次或100次读取一次。

如果您的序列化程序不支持取消,您可以执行以下操作:

  • 在获取数据的上层支持取消

例如,对于WebClient,可以利用WebClient.CancelAsync等。。。

相关内容

  • 没有找到相关文章

最新更新