2014-10-03 89 views
1

程序集A包含對程序集B的引用。程序集A子類 - Class1 - 程序集B中。程序集C還包含相同的基類 - Class1。不同的實現和可能不同的虛擬方法被重寫爲Class1也是子類。一分鐘讓我們假設我很生氣,想在運行時換掉基類實現,替換組件A中引用的內容。在運行時重新定義基類

我調查了assembly redirection,因爲程序集B已簽名且程序集C未簽名,因此失敗。

我無法反編譯代碼併合並程序集,因爲有太多問題需要解決,例如而不是,所有類的定義都很容易被發現。由於需要子類,我不能使用CSharpCodeProvider類,因此需要反編譯。 Reflection.Emit太複雜了,我需要反編譯。

一個選項是獲取子類的副本並根據某個開關執行動態編譯,在代碼中添加任意引用並將結果輸入爲動態。然後子類生活在一個動態的對象中,但是由於與另一個系統的交互,我有這種可怕的感覺,它需要在編譯時或至少在更早的時候纔可用。該代碼由另一個系統調用,該系統可能在啓動時使用Assembly.Load加載重寫的程序集或其他任意點。

使用Assembly.Load動態加載程序集引發了各種問題,你甚至可以用這種方式使用反射來代替基類嗎?

有沒有人知道一個可行的解決方案?

編輯: 更多的上下文 - 問題是我們有一些虛擬方法的覆蓋,將其推廣到數千個盒子。幾百個盒子需要基類的不同實現,目前需要進行2次部署才能應用各種腳本來解決這個問題。其目標是爲所有部署提供二進制相同的dll,最好找到一種使用config在需要時切換實現的方式,而不是在數千次安裝中更改dll,這需要軟件重新啓動,可能會中斷業務和創建支持問題。之前已經犯了一個錯誤,我無法改變單片架構。

+3

而不是說:「這是我爲了解決我的實際問題而瘋狂的想法」,而是告訴我們更多關於真實問題本身的信息。動態交換基類感覺就像是一個令人討厭的解決方案,即使你可以讓它工作,它也可能非常脆弱。那麼,你真的想做什麼? – 2014-10-03 16:37:22

+1

*爲什麼*你需要不同的基類嗎?這是一個非常奇怪的要求 - 事實上,我不記得以前需要什麼。例如,這可以通過組合而不是繼承來處理嗎? (這通常是我的第一種方法,如果繼承造成困難......) – 2014-10-03 16:46:06

+0

+1組成。作文真的是你的朋友。 – 2014-10-03 16:49:40

回答

1

該解決方案不是子類。依賴關係在定義上是靜態的,應該保持原樣。你想實現的是一個很好的選擇,通過interface將接口從實現中分離出來,並將依賴關係降級到has-a。然後你可以使用delegation pattern來完成任務。

這是constructor injection的一個快速示例,它是dependency injection的特例。

interface IAnimal 
{ 
    int DoSomething(); 
} 

class Bobcat implements IAnimal 
{ 
    private IAnimal _a; 

    public Bobcat(IAnimal a) // inject the dependency through the constructor 
    { 
     this._a = a; 
    } 

    public int DoSomething() // implement IAnimal 
    { 
     return _a.DoSomething(); // delegate to _a 
    } 
} 

構造函數注入的好處是,你保證有一個IAnimal實現。現在,您可以添加一個方法setter injection

public SetAnimal(IAnimal a) 
{ 
    this._a = a; // hot-swap the IAnimal implementation 
} 

您現在可以設置在建築(在運行時),並在執行過程中甚至熱插拔執行它。如果您在所有Bobcat實例上共享單個a實例,則可以獲得其他功能。

所有這些點是用動態has-a依賴性,這仍產生其行爲完全相同的情況下(即,有其它類的方法)來取代靜態is-a依賴性。以下是關於delegation pattern的更多信息。

+0

對不起,這是一個很好的建議,但我認爲我需要繼承發生,因爲另一個系統 - 我無法更改代碼 - 消耗執行重寫的程序集,並且僅因繼承而調用更新後的代碼。外部系統提供了包含虛擬方法的dll,我們可以通過覆蓋不同的程序集來覆蓋實現,然後使用config告訴系統尋找新的實現。 – 2014-10-03 16:57:05

+0

事情是我不能只是不改變代碼,我不能改變2個程序集中的代碼,其中一個需要根據條件加載,即代碼運行在世界的哪個部分 – 2014-10-03 17:04:42

+0

我承認我的解決方案是架構性的,需要重新設計和實現代碼。 – pid 2014-10-03 17:06:09

1

聽起來像@pid的解決方案是你的問題是它不能與Activator.CreateInstance一起使用。

解決方法是在構造函數內部進行注入(如果可以調用它)。

這不是我會在我完全控制的系統中部署的解決方案,您還可以通過用某種運行時代碼IL代替Activator.CreateInstance來優化此代碼(這將導致(字面上)性能更好幾千倍)。

public class Foo() 
{ 
    private IImplementFoo _implimentation; 
    public Foo() 
    { 
     var implimentationTypeName = ConfigurationManager.AppSettings["Foo"]; 
     var implimentationType = GetType(implimentationTypeName); 
     _implimentation = (IImplementFoo) Activator.CreateInstance(implimentationType); 

    } 

    public void Bar() 
    { 
     _implimentation.Bar(); 
    } 
}