简体   繁体   中英

C# change type of child class in parent(abstract) class

Code:

abstract class Parent{
    void changeChild(){

    }
}
class Child1: Parent{
}
class Child2: Parent{
}
//-----
Parent parent = new Child1(); //instantiated as Child1
parent.changeChild(); //change type of this class to Child2

so parent should be instance of Child2 class.

I understand that Child1 can be different from Child2(more/less fields, methods), but I just want to call constructor on this object, which is not allowed.

simple

parent = new Child2();

could be done, but there is like 10 child classes(Growing) and I want to move this into parent class

Is this somehow possible in c#?

Thanks

You can't change the type of an existing object, but you can create a new object and return it.

Example:

abstract class Parent{

  Parent ChangeChild<T>() where T : Parent {
    if (typeof(T) == typeof(Child1)) {
      return new Child1(this);
    if (typeof(T) == typeof(Child2)) {
      return new Child2(this);
    } else {
      throw new NotImplementedException("Unhandled type");
    }
  }

}

class Child1: Parent{
  public Child1() {} // create
  public Child1(Parent source) {} // convert
}

class Child2: Parent{
  public Child2() {} // create
  public Child2(Parent source) {} // convert
}

Parent parent = new Child1();
parent = parent.ChangeChild<Child2>();

Well, if you want just that ctor is called automaticcally, should be enough to wtrite something, like

class Child1: Child2{
}

class Child2: Parent{
}

So you have Child2 ctor that will be called when Child1 is constructed. But it's completely different architecture design in regard if yours.

If it's not somethign you're asking for, please clarify.

Automapper might be your best bet.

T changeChild<T>() : Parent{
   // change the type here.
}

Would something like this work?

abstract class Parent {
    private Parent Proxy;
    public void ChangeChild<T>() where T : Parent, new() {
        Proxy = new T();
    }
}

You'd have to use the Proxy object to call members and properties.

You cannot do it like this. Perhaps you could create Parent as a wrapper class

class Parent
{
    Parent _child;

    public Parent(Parent child)
    {
        _child = child;
    }

    public void ChangeChild(Parent child)
    {
        _child = child;
    }

    public string AProperty {
        get { return _child.AProperty; }
        set { _child.AProperty = value; }
    }

    public int AMethod(int x)
    {
        return _child.AMethod(x);
    }
}

And then

Parent parent = new Parent(new Child1());
parent.AProperty = "hello";
int y = parent.AMethod(55);

parent.ChangeChild(new Child2());

Note: The parent should not have knowledge about the specific children in a good OO-design. This ensures that you can create new children later (say Child3 ) without having to change Parent .

However, if this is not an issue for you and you want the parent to care automatically about changing children then change or overload the constructor with

    public Parent()
    {
        _child = new Child1();
    }

and change or overload ChangeChild with

    public void ChangeChild()
    {
       if (_child is Child1) {
           _child = new Child2();
       } else {
           _child = new Child1();
       }
    }

If you need to change type of some object in runtime, it's not case for inheritance. You should use composition here. Try something like Strategy (if Parent class represents some behavior).

public class Foo
{
    // provide default value (or inject it via ctor)
    private Parent _parent = new Child1(); 

    public void ChangeChild(Parent parent){
        _parent = parent;
    }

    public void Bar()
    {
        _parent.DoSomething();  
    }
}

public abstract class Parent
{
    public abstract void DoSomething();
}

public class Child1: Parent
{
    public override void DoSomething() { ... }
}

public class Child2: Parent
{
    public override void DoSomething() { ... }
}

And now you can change type of dependency at runtime:

Foo foo = new Foo(new Child1());
foo.Bar(); // child1 implementation used
foo.ChangeChild(new Child2());
foo.Bar(); // child2 implementation used

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM