可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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);
}
回答1:
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.
回答2:
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;
}
回答3:
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".
回答4:
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.
回答5:
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).
回答6:
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.