2010-12-10 73 views
0

听起来很愚蠢的想法,但我想知道是否有可能以某种方式。运行时更换/交换基类与另一个基类

是否有可能在运行时更改派生类的基类?当然,有很多ifs和buts以及为什么有人会这么做,它的设计很糟糕以及所有这些问题。

让所有人保持缄默(尽管他们可能是完全有效的),让我们说,只是踢或显示你的书呆子,是否可能在C#或任何语言的事情呢?

因此,像:

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

现在,这是一些自修改的代码! “我是哺乳动物!” “不,等等......我是爬行动物!” “哦,现在我想成为一只鸟!” – 2010-12-10 17:19:39

+1

你应该考虑继承的构成。 – 2010-12-10 17:47:53

+0

目前还没有真正的用例。即使我同意它完全不好的设计。我问这个问题的原因是因为我听到有人说出来,并声称他们已经做到了(可能用C++)。即使我非常认为他是个出色的家伙,他也无法相信他。我已经尝试了很多东西,并且在将其视为“不可能”之前,希望得到社区的意见。 DLR的想法似乎很有趣。将在周末做一些挖掘工作,看看能否做些什么。 – Mrchief 2010-12-10 20:03:29

回答

0

我能想到的最接近的事是:

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) { } 
} 

我不知道如果动态语言运行时可以做任何你想要它做什么。

最近你可以得到将 通过 至少一个定义为一个接口,然后从一个到另一个派生 铸造从两种类型的派生。

我不得不同意,根据这个建议会满足他想做的事情,这也是一个更好的设计,那么他真正想做的事情。

+0

将尝试玩DLR。谢谢。 – Mrchief 2010-12-10 20:06:30

+0

这是最接近答案... – Mrchief 2011-01-24 16:07:54

1

这是不可能在C#。可能你想要的更多的是基于原型的解决方案,这些解决方案通常在JavaScript等动态语言中找到,您可以通过添加其定义的方式来“扩展”对象的功能。

但是为了完成你的代码提示,你可以让可交换类继承自一个共同的祖先类。这样你可以将每个实例分配给他们的后代。

public class baseClassAncestor{ 

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

public class baseSwapped:baseClassAncestor { 
    public int sillyNumber; 
} 

public class derivedClass : baseOriginal { 
    public bool iAmDumb; 
} 
0

最接近你可能会从两种类型中派生出来,定义至少一个作为接口,然后从一个派生到另一个派生。

1

通过使用派生类加载实现基类BEFORE的不同程序集,可以执行一次性基类交换。但是这种方法不会使你的确切代码正常工作,因为你不能编译它 - 但是可以使访问不同基类的方法来分离函数。

您可以添加包含所有基类的所有可能的方法/属性的UnionBase类,以便您可以使用此类针对程序集编译Main代码。与运行时相比,您可以加载包含特定基类的程序集。

正常警告:您需要有非常好的理由和理解走这条路线。即现有的外部代码是考虑这种方法的理由。

“不要在家里做,在训练有素的专业人士在封闭的课程上进行。

1

还有一个可能的解决方法可以使用基于在编译时weaving,即PostSharp,其能够无缝地注入新的方法和接口对现有类型以及修改(截距)现有的一些AOP溶液来实现。

+0

是啊,这跨越了我的想法。虽然我还没有尝试交换基类。 – Mrchief 2010-12-12 05:14:12

1

实际上你可能想要交换基类的一个很好的理由。假设你想修改基类,但是你不想扰乱当前的代码库,因为它在其他团队之间共享。假设有10多个派生类从基地继承。您可以创建10个以上的自定义派生类来覆盖基类,但这是很多工作。这是你做的。问题的关键是创建一个接口和一个基本代理类。

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(); 
} 

其结果将是如下

base1 open 
base2 open 

UPDATE: 虽然这个答案的工作,但现实是,继承引入耦合这充其量使得这项工作难度。另外,在一个实际的场景中,你的需求可能导致你想从多个基类中派生出来,这在c#中是不可能的。如果你想交换基类,你最好使用桥接设计模式(这实际上避免了继承,从而避免了耦合)。

+0

如果我有良好的意图和合法地做事,我会这样做。我的问题最初没有这样的意图! :)我已经意识到,编译后的代码表达式可能是另一个可行的黑魔法途径,但还没有时间来纠正。 – Mrchief 2015-11-03 15:36:30