2010-12-10 72 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