I am trying to write a method that can copy an existing class into a new one, but without a reference to the source class.
There are many samples out there, but in my case the source and target objects are defined as a baseclass while they are created as an endclass.
My classes are like this
// my baseclass
public partial class ModelBase
{
[JsonIgnore]
public RowStatus Status { get; set; }
}
// one of my endclasses
public class ModelUser: BaseClasses.ModelBase
{
public int? UserID { get; set; }
public string UserFirst { get; set; }
public string UserLastname { get; set; }
}
// and there are many more that derive from ModelBase off course...
What I would like is that in a Base Form (where all other forms will derive from) I can copy an existing model into a new one, without a reference to the existing one.
So I tried to do this using serializing/deserializing, which works well, but only if you know the exact type, and in my BaseForm I do not have the exact type yet, there I work with an instance declared as ModelBase, but created in a derived form as ModelUser for example.
In other words, I have a base form like this
public partial class FormMVBaseDetail
{
protected ModelBase model = null;
protected ModelBase _originalModel = null;
...
private void FormMVBaseDetail_Shown(object sender, EventArgs e)
{
_originalModel = CloneModel(model);
}
protected ModelBase CloneModel(ModelBase model)
{
string json = JsonConvert.SerializeObject(model);
return JsonConvert.DeserializeObject<ModelBase>(json);
}
}
public partial class FormMVBaseUser : FormMVBaseDetail
{
model = new ModelUser();
...
// somewhere in the code some properties of model could change...
private void button1_Click(object sender, EventArgs e)
{
// Now I would like that _originalModel is an exact copy of model
// So _originalModel should be of type ModelUser, not ModelBase
// How to achieve that without additional code in FormMBaseUser ?
if (_originalModel.UserFirst != model.UserFirst)
{ // do something }
}
}
The first attempt is this
public ModelBase CloneModel(ModelBase model)
{
string json = JsonConvert.SerializeObject(model);
return JsonConvert.DeserializeObject<ModelBase>(json);
}
this has the problem that, allthough the parameter model
is created as new ModelUser()
the deserialize will make it a ModelBase
which only has one public property, the Status.
If I would do this, then it would work, but only for ModelUser
public ModelBase CloneModel(ModelBase model)
{
string json = JsonConvert.SerializeObject(model);
return JsonConvert.DeserializeObject<ModelUser>(json);
}
This is not usefull in a baseform.
So the next thing I tried is this
public object CloneModel(ModelBase model)
{
string json = JsonConvert.SerializeObject(model);
return JsonConvert.DeserializeObject<object>(json);
}
The idea was to use it like this
ModelBase _originalModel = null;
_originalModel = (ModelBase)CloneModel(CurrentModel);
but for some reason it always deserializes as Newtonsoft.Json.Linq.JObject
in stead of object
, so this also does not works for me.
How could I achieve this ?
I have read this links, but they did not get me any further
How do I use reflection to call a generic method?
Passing just a type as a parameter in C#
How can I use an expression tree to call a generic method when the Type is only known at runtime?
Use variable as Type
CodePudding user response:
You can use the non-generic version of JsonConvert.DeserializeObject()
It take the string in first parameter and the type in second one.
So your clone function will be like this:
public object CloneModel(ModelBase model)
{
string json = JsonConvert.SerializeObject(model);
return JsonConvert.DeserializeObject(json, model.GetType());
}
CodePudding user response:
The generic version of Ygalbel's answer would be this:
public partial class FormMVBaseDetail<T> where T : ModelBase
{
protected T _model;
protected T _originalModel;
public T CloneModel(T model)
{
var json = JsonConvert.SerializeObject(model);
return JsonConvert.DeserializeObject<T>(json);
}
}
Whether you want the base class to be generic will depend on your needs.
Usage:
public partial class FormMVBaseUser : FormMVBaseDetail<ModelUser>
{
_model = new ModelUser();
// Other code as before