Change/Swap base class at runtime with another bas

2019-09-13 16:17发布

Sounds like silly idea but I was wondering if it's possible somehow.

Is it possible to change the base class of a derived class at runtime? Of course, there are lot of ifs and buts and the the question of why would someone do it and its a bad design probably and all that.

Keeping all those aside (even though they might be perfectly valid), let's say, just for kicks or to show your nerdiness, is it possible in C# or any language for that matter?

So something like:

public class baseOriginal {
    public string justAProperty;
}

public class baseSwapped {
    public int sillyNumber;
}

public class derivedClass : baseOriginal {
   public bool iAmDumb;
}

void Main() {
    baseOriginal derived = new derivedClass ();
    Console.WriteLine(derived.justAProperty);
    baseSwapped derivedSwapped = (??);
    Console.WriteLine(derivedSwapped.sillyNumber);
}

标签: c# oop class
6条回答
聊天终结者
2楼-- · 2019-09-13 16:27

It isn't possible in C#. Probably what you want is more of a prototype-based solution commonly found in dynamic languages like JavaScript where you can "extend" the functionality of the object by adding to how it's defined.

But to accomplish what your code hints at doing, you can have the swappable classes inherit from a common ancestor class. That way you can assign instances of each to their decendents.

public class baseClassAncestor{

}
public class baseOriginal:baseClassAncestor { 
    public string justAProperty; 
} 

public class baseSwapped:baseClassAncestor  { 
    public int sillyNumber; 
} 

public class derivedClass : baseOriginal { 
   public bool iAmDumb; 
} 
查看更多
Rolldiameter
3楼-- · 2019-09-13 16:27

One more possible workaround could be implemented using some AOP solution that is based on compile-time weaving, i.e. PostSharp, which is able to seamlessly inject new methods and interfaces to existing types as well as modify (intercept) existing ones.

查看更多
萌系小妹纸
4楼-- · 2019-09-13 16:35

Closest you could get would be to derive from both types by defining at least one as an interface, then casting derived from one to the other.

查看更多
劫难
5楼-- · 2019-09-13 16:37

The closest thing I can think of is the following:

http://msdn.microsoft.com/en-us/library/dd264736.aspx

static void Main(string[] args)
{
    ExampleClass ec = new ExampleClass();
    // The following line causes a compiler error if exampleMethod1 has only
    // one parameter.
    //ec.exampleMethod1(10, 4);

    dynamic dynamic_ec = new ExampleClass();
    // The following line is not identified as an error by the
    // compiler, but it causes a run-time exception.
    dynamic_ec.exampleMethod1(10, 4);

    // The following calls also do not cause compiler errors, whether 
    // appropriate methods exist or not.
    dynamic_ec.someMethod("some argument", 7, null);
    dynamic_ec.nonexistentMethod();
}

class ExampleClass
{
    public ExampleClass() { }
    public ExampleClass(int v) { }

    public void exampleMethod1(int i) { }

    public void exampleMethod2(string str) { }
}

I have no idea if the dynamic language runtime can do what you want it to do.

Closest you could get would be to derive from both types by defining at least one as an interface, then casting derived from one to the other.

I would have to agree, based on the example this suggestion would satisfy what he wants to do, it also is a better design then what he actually wants to do.

查看更多
神经病院院长
6楼-- · 2019-09-13 16:38

You can do one time base class swap by loading different assemblies that implement base class BEFORE using derived class. But this approach will not make your exact code working as you will not be able to compile that - but moving access to methods of different base classes to separate functions could be made working.

You add UnionBase class that contains all possible methods/properties from all base classes so you can compile your Main code against the assembly with this class. Than at run time you load assembly that has contains your particular base class.

Usual warning: You need to have very good reasons and understanding for going this route. I.e. existing external code is a reason to consider such approach.

"Don't do it at home, performed on a closed course by trained professional".

查看更多
一纸荒年 Trace。
7楼-- · 2019-09-13 16:52

There is actually a good reason where you may want to swap the base class. Let say you want to modify the base class but you don't wan't to perturb the current code base as it is shared among other teams. Let say there are 10+ derived class that inherits from base. You could create 10+ custom derived classes to override the base class but that is a lot of work. Here is what you do. The key to the problem is to create an interface and a base proxy class.

class Program
{
    static void Main(string[] args)
    {
          IActionable action = new Derived<Base1>();
          action.open();
          action = new Derived<Base2>();
          action.open();

     }
}

 // Proxybase is a fake base class. ProxyBase will point to a real base1 or
 // base2
public class Derived<T>:ProxyBase,IActionable
{
    public Derived():base(typeof(T))    

    // the open function is not overriden in this case allowing
    // the base implementation to be used
}

// this looks like the real base class but it is a fake
// The proxy simply points to the implementation of base1 or base2 instead
public abstract class ProxyBase: IActionable
{
    IActionable obj;
    public ProxyBase(Type type,params object[] args)
    {
             obj = (IActionable)Activator.CreateInstance(type,args);   
    }

    public virtual void open()
    {
          obj.open();
    }
}

// notice base1 and base2 are NOT abstract in this case
// consider this the original implementation of the base class
public class Base1: IActionable
{
      public virtual void open()
      {
            Console.WriteLine("base1 open");
      }

}

// here base2 acquired the functionality of base1 and hides base1's open 
   function
// consider this implementation the new one to replace the original one
public class Base2: Base1, IActionable
{
     public new virtual void open()
     {
           Console.WriteLine("base2 open");
     }
}

public interface IActionable
{
    void open();
}

The result would be as follows

base1 open
base2 open

UPDATE: Although this answer works, the reality is that inheritance introduces coupling which makes this exercise difficult at best. Also, in a practical scenario, your requirements may lead you to want to derive from multiple base class which is not possible in c#. If you want to interchange the base class you are best to use the bridge design pattern (which in fact avoids inheritance altogether thus avoiding the coupling).

查看更多
登录 后发表回答