2010-05-03 8 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. Он будет вызывать оригинальный метод на AB, если вы не передадите его ABChild. – RationalGeek

2

Я бы посмотрел PostSharp. Он может «перепрограммировать» существующие скомпилированные сборки, чтобы добавить вид до и после обработки, который вы ищете. Я не уверен на 100%, что это будет отвечать вашим потребностям, но это очень хорошо.

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

+1

Для этого требуется, чтобы сборка была приписана, так как это то, как пост резко определяет, что переписывать. –

+0

@Reed: вы можете использовать атрибуты уровня [assembly:] с PostSharp. Тем не менее, они, вероятно, должны войти в AssemblyInfo.cs сборки. – TrueWill

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', будут продолжать использовать исходный класс. –

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 требуется вызывающему, больше может потребоваться выразить через оболочку. –

+0

@jdk: Может потребоваться больше, но в вопросе не было указано, поэтому я не включил его :) Кроме того, ваш gravatar выглядит так же, как моя татуировка :) –

+0

Если ваш образ татуировки был опубликован в Интернете, тогда я украл его как мой Граватар. Я могу только дать +1 вашему ответу один раз, иначе я бы выделил секунду для крутой татуировки! :) –

2

Вы можете использовать динамический прокси-сервер, такой как Castle Proxy.

0

Вы можете реализовать динамический прокси. Дополнительная информация here

В основном вы распространяете базовый класс и переопределяете некоторые методы своими. Теперь вам нужно повторно назначить объект, вызываемый вашим экземпляром, и все вызовы сначала пройдут через ваш объект.

0

Может быть, один из решений Аспект-ориентированное программирование (АОП) из этого Stackoverflow thread пригодятся ...

Смежные вопросы