Home > Mobile >  how to copy a baseclass to an endclass without reference?
how to copy a baseclass to an endclass without reference?

Time:09-17

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
  • Related