如何强制c#NewtonSoft反序列化器使用已创建的对象进行反序列化

时间:2018-04-24 13:18:05

标签: c# json serialization reflection json.net

在做的时候

JsonConvert.DeserializeObject(value, type);

为给定的type创建了一个用于反序列化的新对象。我的要求是什么,我想使用已经创建的反序列化对象

CustomObject obj = new CustomObject(); //passing constructor args
JsonConvert.DeserializeObject(value, obj);    

但是这种超载是不可用的。

那么,是否有任何解决方法以便我可以使用已创建的对象而不是通过反序列化器创建新类型。

为什么我要这样做? (描述)

我正在编写从JSON到c#类的通用映射器。 JSON的结构类似于

  {
    "ActionType" : "LogEvent", //this is actually class name in a specific namespace
    "Settings"   : {
           "FailureRetries" : 4,
           "LogChannel"     : 1234 // log channel id, implementation detail
     }
  }

我在配置映射器中的操作如下

public void IAction GetActionFromConfig(){

    dynamic config = configManager.Load<dynamic>(); //loads JSON file.
    string className = config.ActionType; //from config we will get file name.
    Type type = Type.GetType(nameSpaceForConfig + "." + className);

    string  settingValue = JsonConvert.SerializeObject(config.Settings);
    object actionObject = JsonConvert.DeserializeObject(settingValue, type);

    return (IAction)actionObject; // return the IAction from config.
}

我的问题是IAction实现类可能在构造函数中有一些依赖项(例如ILogger),默认情况下,反序列化不会初始化构造函数参数。我知道我可以覆盖构造函数初始化的JsonConverter但是当我编写通用映射器时,我无法使用自定义JsonConverter来提供特定参数。

我打算做的是首先创建一个字典,将Type(c#Type类)映射到特定的依赖项解析实现。

其次,我将获得给定操作类型的构造函数(在带有ActionType参数的config中给出的类型)

Type type = Type.GetType(nameSpaceForConfig + "." + className);
var ctors = typeof(type).GetConstructors();
var ctor = ctors[0];
List<Type> constructorArguments = new List<Type();
foreach (var param in ctor.GetParameters())
{
     constructorArguments.Add(param.ParameterType);
}

然后我将查询在步骤1中创建的字典以获取构造函数的参数。

最后,我将使用Activator.CreateInstance()(传递上一步中获得的构造函数依赖项)。

然后使用此对象进行反序列化,以通过配置文件初始化公共属性。

因此,这就是我需要在object而不是type上进行反序列化的原因。

注意:前置条件是每个操作都应该有一个包含所有依赖项的构造函数。

除此之外:configManager.Load<T>实施

public T Load<T>() where T : class, new() => Load(typeof(T)) as T;
public object Load(Type type)
{
  if (!File.Exists(_configurationFilePath))
    return Activator.CreateInstance(type);

  var jsonFile = File.ReadAllText(_configurationFilePath);

  return JsonConvert.DeserializeObject(jsonFile, type, JsonSerializerSettings);
}

1 个答案:

答案 0 :(得分:3)

您应该使用JsonConvert.PopulateObject方法填充现有对象。请参阅here