While doing
JsonConvert.DeserializeObject(value, type);
A new object is created of given type
for deserialization. What my requirement is I want to use already created object for deserialization
CustomObject obj = new CustomObject(); //passing constructor args
JsonConvert.DeserializeObject(value, obj);
But this overload is not available.
So, is there any workaround so that I can use the already created object instead of creating new type through Deserializer.?
Why do I want to do so? (Detail)
I am writing a generic mapper from JSON to c# classes. Structure of JSON looks like
{
"ActionType" : "LogEvent", //this is actually class name in a specific namespace
"Settings" : {
"FailureRetries" : 4,
"LogChannel" : 1234 // log channel id, implementation detail
}
}
What I do in the configuration mapper is as follows
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.
}
My problem is the IAction
implementation classes might have some dependencies in the constructor (such as ILogger
) and by default, deserialization won't initialize the constructor parameter. I know I can override the JsonConverter
for the constructor initialization but as I am writing a generic mapper I can't give the specific arguments using custom JsonConverter
.
What I am planning to do is first create a dictionary that will map Type
(c# Type
class) to a specific implementation for dependency resolution.
Second I will get the constructors of given action type (type given in config with ActionType
parameter)
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);
}
Then I will query the dictionary created in step 1. to get the arguments for the constructor.
Finally, I will use the Activator.CreateInstance()
(passing the constructor dependencies got in previous step).
And then use this object for deserialization to initialize the public properties through the config file.
So, this is why I require deserialization to happen on the object
not on the type
.
NOTE: Pre-condition is each action should have one constructor with all the dependencies.
Aside: configManager.Load<T>
implementation
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);
}
Aucun commentaire:
Enregistrer un commentaire