我正在使用Newtonsoft Json.NET
库反序列化大量数据。性能是高优先级,因此所有模型类都通过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
进行反序列化的构造函数重载吗?
答案 0 :(得分:1)
由于您在此处使用的是“示例”类型:
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更快
答案 1 :(得分:1)
除了约束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;
}
}
}