[英]C# Generic Deserializer by calling static methods
我正在使用Newtonsoft Json.NET
庫反序列化大量數據。 性能是高度優先的,因此所有模型類都可以通過JsonReader
手動反序列JsonReader
。 每個模型類都有其自己的靜態構造方法FromJson
,該方法接受JsonReader
進行讀取。
class Example
{
public Guid? Id { get; private set; }
public DateTime? Date { get; private set; }
public decimal? Amount { get; private set; }
public static Example FromJson(JsonReader reader)
{
var example = new Example();
reader.SkipToStartObject(); // Extension method, skips to first JsonToken.StartObject
while(reader.Read() && reader.TokenType == JsonToken.PropertyName)
{
var propertyName = reader.Value.ToString();
switch(propertyName)
{
case "id":
example.Id = reader.ReadAsGuid(); // Extension method
break;
case "date":
example.Date = reader.ReadAsDateTime();
break;
case "amount":
example.Amount = reader.ReadAsDecimal();
break;
default:
break;
}
}
return example;
}
}
我想以某種方式接口該類,以便我可以編寫一個采用該接口並自動調用FromJson()
方法的通用解串器。 理想情況下,我將能夠以這種方式徹底反序列化WebResponse
。
var response = await request.GetResponseAsync();
var stream = response.GetResponseStream();
return GenericJsonDeserializer.Deserialize<Example>(stream);
GenericJsonDeserializer
會將允許的類型限制為僅具有接口的類型,從流中設置JsonReader
,使用FromJson
方法反序列化,然后返回對象。
一個問題是C#接口不允許必需的構造函數,也不允許靜態方法。 因此,我不能限制GenericJsonSerializer
。
通過反射可以解決該問題,但這帶來了新問題。 性能至關重要,在這種情況下,我不能使用反射。 在通用方法內部創建一個新實例將是:
Activator
;或者 FromJson
函數並調用它,這可能甚至更慢。 無論哪種情況,通過發出IL來編譯DynamicMethod
最佳選擇(並且可能提供最佳性能),但我想盡可能避免這種情況。
我還有其他方法可以約束通用方法以要求靜態構造函數或接受JsonReader
進行反序列化的構造函數重載嗎?
由於您在此處使用類型“示例”:
GenericJsonDeserializer.Deserialize<Example>(stream);
您可以使用:
Example.FromJson
因為您仍然需要知道類型。
只需制作一個接受Stream和JsonReader或其他版本的版本即可。 如果需要,您可以與其他靜態類共享創建JsonReader的邏輯。
還有另一種方法。 您可以將FromJson方法移動/提取到另一個類/接口:
interface IMyJsonDeserializer
{
void FromJson(Stream stream, out ExampleClassA result);
void FromJson(Stream stream, out ExampleClassB result);
}
class MyJsonDeserializer : IMyJsonDeserializer
{
public void FromJson(Stream stream, out ExampleClassA result)
{
// code to deserialize
}
public void FromJson(Stream stream, out ExampleClassB result)
{
// code to deserialize
}
// .. more methods
}
用法:
var deserializer = new MyJsonDeserializer(); // you can create it just once somewhere
ExampleClassA a;
deserializer.FromJson(stream, out a);
ExampleClassB b;
deserializer.FromJson(stream, out b);
如果您有很多類,則可以進行一些接口隔離和繼承。 現在,您可以共享使用OOP方法從Stream創建JsonReader的邏輯。
如果您確實喜歡香水,可以看看Utf8Json 。 事實證明,它比Newtonsoft.Json更快。
除了約束ctor外,您還可以約束到initialize方法:
自引用約束不是真的必要
public interface IDeserializable<T> where T : IDeserializable<T>, new()
{
T FromJson(JsonReader reader);
}
然后修改Example
來實現該接口:
public class Example : IDeserializable<Example>
{
//...
public Example FromJson(JsonReader reader)
{
// populate the object with json...
// you can create complex object like this:
// this.Example2 = new Example2().FromJson(reader);
return this;
}
}
最后,如下定義Deserialize
方法:
public static class GenericJsonSerializer
{
public static T Deserialize<T>(Stream steam) where T : IDeserializable<T>, new()
{
using (var reader = ...)
{
var result = new T();
result.FromJson(reader);
return result;
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.