Каков наилучший способ выполнения последовательных методов?
Вопрос
Работа над проектом, в котором последовательный набор методов должен выполняться каждые x
секунды. Прямо сейчас у меня есть методы, содержащиеся в другом «родительском методе», и я просто последовательно вызываю их сразу после другого.
class DoTheseThings()
{
DoThis();
NowDoThat();
NowDoThis();
MoreWork();
AndImSpent();
}
Каждый метод должен успешно работать без исключения, прежде чем можно будет выполнить следующий шаг. Итак, теперь я обернул каждый из этих методов с помощью while
и try..catch
, а затем в catch
снова выполнил этот метод.
while( !hadError )
{
try
{
DoThis();
}
catch(Exception doThisException )
{
hadError = true;
}
}
Это кажется вонючим и не очень сухим. Есть ли лучший способ сделать это, чтобы я не упаковывал новые функции в те же методы. Не является ли какая-то коллекция делегатов правильным способом реализации этого? Р>
Есть ли более "правильный" вариант? решение? р>
Решение
Action[] work=new Action[]{new Action(DoThis), new Action(NowDoThat),
new Action(NowDoThis), new Action(MoreWork), new Action(AndImSpent)};
int current =0;
while(current!=work.Length)
{
try
{
work[current]();
current++;
}
catch(Exception ex)
{
// log the error or whatever
// maybe sleep a while to not kill the processors if a successful execution depends on time elapsed
}
}
Другие советы
Не является ли какая-то коллекция Delegate правильным способом для реализации этого?
Делегат - это возможный способ решения этой проблемы.
Просто создайте делегата что-то вроде:
открытый делегат void WorkDelegate ();
и поместите их в arraylist, который вы можете перебирать.
У меня есть личное религиозное убеждение, что вы не должны ловить System.Exception, или, точнее, вы должны ловить только те исключения, которые вы знаете, как обрабатывать.
При этом я собираюсь предположить, что каждый из методов, которые вы вызываете, выполняет что-то свое и может привести к возникновению разных исключений. Это означает, что вам, вероятно, понадобятся разные обработчики для каждого метода.
Если вы также следуете моей религии, и второе утверждение верно, то вы не повторяете код без необходимости. Если у вас нет других требований, мои рекомендации по улучшению вашего кода:
1) Поместите try-catch в каждый метод, а не в каждый вызов метода.
2) Пусть уловы внутри каждого метода ловят ТОЛЬКО те исключения, о которых вы знаете. Р>
http://blogs.msdn.com/fxcop /archive/2006/06/14/631923.aspx http://blogs.msdn.com/oldnewthing/archive/ 2005/01/14 / 352949.aspx http://www.joelonsoftware.com/articles/Wrong.html
HTH ...
Ваш пример выглядит нормально ... он сухой, но хорошо справится с работой !! на самом деле, если эти методы выполняют доступ к базе данных .. вы можете использовать транзакцию для обеспечения целостности ...
если вы имеете дело с общими переменными для многопоточных программ ... лучше использовать синхронизацию ... самое важное в кодировании - это то, что вы пишете правильный код ... с меньшим количеством ошибок ... и будете выполнять задачу правильно ..
public void DoTheseThings()
{
SafelyDoEach( new Action[]{
DoThis,
NowDoThat,
NowDoThis,
MoreWork,
AndImSpent
})
}
public void SafelyDoEach( params Action[] actions )
{
try
{
foreach( var a in actions )
a();
}
catch( Exception doThisException )
{
// blindly swallowing every exception like this is a terrible idea
// you should really only be swallowing a specific MyAbortedException type
return;
}
}
По какой причине произошла ошибка?
Если бы это была проблема с ресурсами, например, доступ к чему-либо, например, к соединению или объекту, то вы могли бы рассмотреть возможность использования мониторов, семафоров или просто блокировки. Р>
lock (resource)
{
Dosomething(resource);
}
Таким образом, если предыдущий метод обращается к ресурсу, вы можете подождать, пока он не освободит ресурс, чтобы продолжить. Р>
В идеале, вам не нужно запускать цикл для выполнения чего-либо каждый раз, когда происходит сбой. Это вообще не помогает, вы хотели бы знать о проблеме и исправить ее. Иметь цикл, чтобы всегда просто продолжать пытаться, - неправильный путь.
Я бы сделал то, что предлагает Овидиу Пакурар, только я бы использовал цикл foreach
и оставил обработку индексов массивов на усмотрение компилятора.
Простой подход к делегату:
Action<Action> tryForever = (action) => {
bool success;
do {
try {
action();
success = true;
} catch (Exception) {
// should probably log or something here...
}
} while (!success);
};
void DoEverything() {
tryForever(DoThis);
tryForever(NowDoThat);
tryForever(NowDoThis);
tryForever(MoreWork);
tryForever(AndImSpent);
}
Стековый подход:
void DoEverything() {
Stack<Action> thingsToDo = new Stack<Action>(
new Action[] {
DoThis, NowDoThat, NowDoThis, MoreWork, AndImSpent
}
);
Action action;
while ((action = thingsToDo.Pop()) != null) {
bool success;
do {
try {
action();
success = true;
} catch (Exception) {
}
} while (!success);
}