2010-05-03 75 views
4

我需要擴展實例的行爲,但我無法訪問該實例的原始源代碼。例如:C#在運行時更改類方法

/* I don't have the source code for this class, only the runtime instance */ 
Class AB 
{ 
    public void execute(); 
} 
在我的代碼我會攔截每次調用執行,計算一些某些材料,然後調用原來的執行,像

/* This is how I would like to modify the method invokation */ 
SomeType m_OrgExecute; 

{ 
    AB a = new AB(); 
    m_OrgExecute = GetByReflection(a.execute); 
    a.execute = MyExecute; 
} 

void MyExecute() 
{ 
    System.Console.Writeln("In MyExecute"); 
    m_OrgExecute(); 
} 

這可能嗎?

有沒有人有這個問題的解決方案?

回答

0

如果AB不密封,則可以繼承該類並覆蓋該方法。在這種情況下,用新的

class ABChild : AB { 
    public new void execute() { 
     System.Console.Writeln("In MyExecute"); 
    } 
} 

根據該意見,你應該祈求的這個法,ABChild類中:

void Invoke() { 
    ABChild a = new ABChild(); 
    a.execute(); 
} 

希望它可以幫助!

+1

這是行不通的。它會調用AB上的原始方法,除非將其轉換爲ABChild。 – RationalGeek 2010-05-03 16:44:54

2

我會看看PostSharp。它可以「重新連接」現有的編譯程序集,以便添加您正在查找的處理前後的類型。我不是100%肯定它會解決你的需求,但它很可能。

http://www.sharpcrafters.com/aop.net

+1

這需要將程序集歸因於此,因爲這就是post sharp決定重寫的方式。 – 2010-05-03 16:44:39

+0

@Reed:您可以在PostSharp中使用[assembly:]級別屬性。也就是說,那些可能不得不參加大會的AssemblyInfo.cs。 – TrueWill 2010-05-03 16:56:36

2

有沒有辦法通過反射直接做到這一點,等

爲了讓自己的代碼注入這樣,你需要創建自己的組件的修改版本,並使用某種形式的code injection。你不能只是在運行時「改變一個任意程序集的方法」。

0

你總是可以從類繼承並覆蓋execute()方法(如果類不是密封的,而且方法並不至少不公開)。

0

你可以使用一個包裝類:

Class ABWrapper 
{ 
    private AB m_AB; 

    ABWrapper(AB ab) 
    { 
    m_AB = new AB(); 
    } 

    public void execute() 
    { 
    // Do your stuff, then call original method 
    m_AB.execute(); 
    } 
} 

這是一個很好的方法時AB實現了接口(你沒有提到的是,雖然)。在這種情況下ABWrapper應該實現相同的接口。當您使用工廠甚至依賴注入創建您AB情況下,你可以在那裏輕鬆與包裝更換。

5

看起來你想要Decorator pattern

class AB 
{ 
    public void execute() {...} 
} 

class FlaviosABDecorator : AB 
{ 
    AB decoratoredAB; 

    public FlaviosABDecorator (AB decorated) 
    { 
     this.decoratedAB = decorated; 
    } 

    public void execute() 
    { 
     FlaviosExecute(); //execute your code first... 
     decoratedAB.execute(); 
    } 

    void FlaviosExecute() {...} 
} 

然後,您需要修改使用AB對象的代碼。

//original code 
//AB someAB = new AB(); 

//new code 
AB originalAB = new AB(); 
AB someAB = new FlaviosABDecorotor(originalAB); 

/* now the following code "just works" but adds your method call */ 
+1

這有一個嚴重的缺點:所有編程使用'AB'的第三方代碼將繼續使用原始類。 – 2013-06-10 09:56:24

1

因爲我喜歡在繼承組成(因爲如果類是密封的繼承可能不是一個選項),我會在我自己的類包裝AB稱爲FlaviosAB是這樣的...

public class FlaviosAB 
{ 
    private AB _passThrough; 
    public FlaviosAB(){ 
     _passThrough = new AB(); 
    } 

    public void execute() 
    { 
     //Your code... 
     Console.WriteLine("In My Execute"); 
     //Then call the passThrough's execute. 
     _passThrough.execute(); 
    } 
} 
+0

這樣可以避免原始類被封閉的任何問題。根據調用者需要的AB的多少其他公共方法,可能需要通過包裝器表示更多。 – 2010-05-03 16:53:17

+0

@jdk:更多可能是必要的,但它沒有在問題中指定,所以我沒有包括它:)此外,你的gravatar看起來就像我的紋身:) – 2010-05-03 16:58:26

+0

如果你的紋身圖像發佈在互聯網上,然後我偷走它作爲我的Gravatar。我只能給你的答案+1,否則我會爲酷紋身提供第二個! :) – 2010-05-03 17:30:51

0

你可以實現一個動態代理。查找更多信息here

基本上,您正在擴展基類並使用您的一些方法覆蓋某些方法。現在,您需要重新分配由您的實例調用的對象,並且所有的調用都將首先通過您的對象。如果執行的調用者()是使用AB

0

從這個Stackoverflow thread面向方面編程(AOP)解決方案能派上用場的也許有......