2016-04-14 24 views
0

我目前使用類似的代碼來反序列化數據流中的數據。取消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文件和連接速度慢?

+0

不完全確定我明白你想要做什麼。如果您使用單線程運行,用戶將如何取消?如果使用多個線程(在.net 3.5中)運行,爲什麼不使用['BackgroundWorker'](https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v = vs.90))。 ASPX)?另見https://msdn.microsoft.com/en-us/library/ywkkz4s1%28v=vs.100%29.aspx – dbc

回答

1

JsonTextReader不支持這個開箱即用,但Json.NET不正確地處理(即重新拋出)例外,從較低級代碼來了,所以你可以繼承讀者和自己動手:

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。見Is it safe to use a boolean flag to stop a thread from running in C#

您希望在投入生產之前測試性能。如果爲每次讀取調用checkCancelled代表不能執行,則可以每10或100次讀取一次。

0

如果你的序列化不支持取消,您可以執行以下操作來代替:

  • 支持消除在獲取數據

例如上層爲WebClient人會利用WebClient.CancelAsync等..