取消 JSON.NET 流反序列化
Cancel JSON.NET stream deserialization
我目前正在使用类似的代码反序列化流中的数据。
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 文件和缓慢的连接,此过程可能需要很长时间?
如果您的序列化程序不支持取消,您可以改为执行以下操作:
- 支持上层取数据取消
例如对于 WebClient
,一个人会利用 WebClient.CancelAsync,等等...
JsonTextReader
不支持开箱即用,但 Json.NET 确实正确处理(即重新抛出)来自较低级别代码的异常,因此您可以子类化 reader 和自己动手:
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
. See Is it safe to use a boolean flag to stop a thread from running in C#。
你我想在将其投入生产之前测试性能。如果为每次读取调用 checkCancelled
委托的性能不佳,您可以为每 10 或 100 次读取调用一次。
我目前正在使用类似的代码反序列化流中的数据。
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 文件和缓慢的连接,此过程可能需要很长时间?
如果您的序列化程序不支持取消,您可以改为执行以下操作:
- 支持上层取数据取消
例如对于 WebClient
,一个人会利用 WebClient.CancelAsync,等等...
JsonTextReader
不支持开箱即用,但 Json.NET 确实正确处理(即重新抛出)来自较低级别代码的异常,因此您可以子类化 reader 和自己动手:
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
. See Is it safe to use a boolean flag to stop a thread from running in C#。
你我想在将其投入生产之前测试性能。如果为每次读取调用 checkCancelled
委托的性能不佳,您可以为每 10 或 100 次读取调用一次。