2010-04-12 5 views
4

Используя C#, мне нужно сделать дополнительную работу, если функция A() была вызвана непосредственно перед функцией C(). Если какая-либо другая функция была вызвана между A() и C(), тогда я не хочу делать эту дополнительную работу. Любые идеи, требующие наименьшего количества дублирования кода?Как автоматически сбросить логическое значение, когда на C# вызывается другой метод?

Я стараюсь избегать добавления строк, таких как flag = false;, в каждую функцию B1 .. BN.

Вот очень простой пример:

bool flag = false; 

void A() 
{ 
    flag = true; 
} 

void B1() 
{ 
    ... 
} 

void B2() 
{ 
    ... 
} 

void C() 
{ 
    if (flag) 
    { 
     //do something 
    } 
} 

Приведенный выше пример просто использовал простой случай, но я открыт для использования нечто иное, чем булевы. Важно то, что я хочу быть в состоянии установить и сбросить флаг рода, так что C() знает, как вести себя соответственно.

Благодарим за помощь. Если вам потребуются разъяснения, я отредактирую свой пост.

+1

Будут ли несколько потоков собираться? т. е. нужно ли это быть потокобезопасным? – womp

ответ

1

Я решил проблему с аналогичной ситуацией (т. Е. Необходимость знать, был ли А вызван непосредственно перед С), имея просто машину состояний на месте. По сути, я построил объект состояния, используя enum и свойство управлять/запрашивать состояние.

Когда был вызван мой эквивалент A(), он должен был бы хранить кусок бизнес-логики из состояния, указывающего, что был вызван A. Если бы были вызваны другие методы (ваши B), это переключило бы состояние на один из нескольких других состояний (моя ситуация была немного сложнее), а затем, когда была вызвана C(), часть бизнес-логики была запрошена, чтобы определить, собирались назвать какой-то метод D(), который содержал функциональность «только если A была просто вызвана».

Я подозреваю, что есть несколько способов решить эту проблему, но мне понравился подход к государственному компьютеру, который я взял, потому что это позволило мне расширить исходную бинарную ситуацию для обработки более сложной ситуации с несколькими состояниями.

Мне повезло, что многопоточность не была проблемой в моем случае, потому что это имеет тенденцию делать вещи более интересными, но государственный автомат, вероятно, будет работать и в этом сценарии.

Только мои два цента.

+0

Оказывается, я смог его решить, используя что-то похожее на это. Я использовал перечисление и нашел более чистое решение, которое не требовало бы функции связи A() и C(). – gtaborga

7

Почему бы просто не разделить вашу «дополнительную работу» на меморизуемую функцию (т. Е. Та, которая кэширует ее результаты)? Всякий раз, когда вам нужна эта работа, вы просто вызываете эту функцию, которая будет короткой, если кеш свежий. Всякий раз, когда эта работа становится устаревшей, аннулируйте кеш. В ваших довольно странных примерах, приведенных выше, я предполагаю, что вам понадобится вызов функции в каждом из B, а один в C. Вызов A приведет к недействительности кеша.

Если вы ищете, чтобы обойти это (то есть какой-то умный способ поймать все вызовы функций и вставить этот вызов), я действительно не стал бы беспокоиться. Я могу представить себе какое-то безумное поколение прокси-класса отражения во времени, но вы должны сделать свой поток кода ясным и очевидным; если каждая функция зависит от уже выполненной работы, просто вызовите «doWork» в каждом из них.

+0

Да, я понял, что нет простого способа сделать это. функции можно вызывать в любом порядке. это только тот конкретный порядок A(), C(), который требует дополнительной работы, но если я устанавливаю флаг в A() и не сбрасываю его, когда вызывается B1() или B2(), то в C() Я получаю неправильное поведение. – gtaborga

+1

+1 для ссылки на отражение; и для «безумной» маркировки, чрезвычайно точной в этом случае;) –

3

Похоже, что ваш дизайн слишком плотно связан, если вызов одного метода изменяет поведение другого, так что вы должны обязательно позвонить им в правильном порядке. Это крупный красный флаг.

Звучит как какой-то рефакторинг в порядке. Немного сложно дать совет, не видя больше реального кода, но вот точка в правильном направлении.

Попробуйте добавить параметр в C следующим образом:

void C(bool DoExtraWork) { 
    if (DoExtraWork)... 
} 

Конечно «DoExtraWork» должен быть назван что-то значимое в контексте вызывающего абонента.

+0

Я видел похожие шаблоны кодирования и * в некоторых случаях *, они оправданы. В конце концов, поведение метода зависит от состояния его класса * * разумно: P –

0

Я не рекомендую это, но то, что ад: Если вы готовы заменить все ваши простой метод вызывает:

A(); 

... с синтаксисом, как это:

// _lastAction is a class-level Action member 
(_lastAction = new Action(A)).Invoke(); 

... то внутри C() вы можете просто сделать чек, как это:

void C() 
{ 
    if (_lastAction.Method.Name == "A") 
    { 

    } 
} 

Это, вероятно, не Автошоу ad-safe (и он не будет работать в коде, запущенном через обфускатор без какого-либо вмешательства), поэтому я не буду использовать что-то вроде этого без тяжелого тестирования. Я также не буду использовать что-то вроде этого периода.

Примечание: моя древняя версия C# имеет только Action<T> (а не Action или Action<T, T> и т.д.), так что если вы застряли там, тоже, вы должны добавить фиктивный параметр для каждого метода использовать этот подход ,

+0

Я согласен, что этот материал грязный, как ад. Я просто не думал о хорошем решении в то время, но я нашел тот, который работал без беспорядка. Спасибо за ваши усилия. – gtaborga