我目前正在使用类似的代码来反序列化流中的数据。
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等。。。