Как мне автоматически сбросить логическое значение, когда любой другой метод вызывается в C #? - PullRequest
4 голосов
/ 13 апреля 2010

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

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

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

bool flag = false;

void A()
{
    flag = true;
}

void B1()
{
    ...
}

void B2()
{
    ...
}

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

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

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

Ответы [ 4 ]

7 голосов
/ 13 апреля 2010

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

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

3 голосов
/ 13 апреля 2010

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

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

Рассмотрите возможность добавления параметра в C следующим образом:

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

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

1 голос
/ 13 апреля 2010

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

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

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

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

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

0 голосов
/ 13 апреля 2010

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

A();

... со следующим синтаксисом:

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

... тогда внутри C() вы можете просто сделать проверку следующим образом:

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

    }
}

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

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

...