위의 대화는 일상적인 작업에서 매우 일반적인 오류 프롬프트 여야합니다.
뒤에있는 작업이 하나의 파일 복사와 같은 간단한 작업 인 경우 재시도 논리를 구현하는 것도 다소 간단합니다.
그러나이 문서에서는 순차 작업 내의 재시도 논리에 대해 설명합니다. 예 : 10 개의 파일 복사, 5 번째 파일 복사 실패 및 메시지 상자 표시, 이제 사용자는 '중단', '다시 시도'또는 '무시'를 결정해야합니다. 그리고 사용자의 응답을 바탕으로 '중단', '재시도'및 '무시'로직을 구현하는 방법에 대해 설명합니다.
배경
최근에 일부 소프트웨어 설치 중에 재시도 버튼과 같은 파일 복사 오류 대화 상자를 보았습니다. 갑자기 이것이 어떻게 좋은 방법으로 구현되어야하는지 생각하기 시작합니다. 우리 모두 알고 있듯이 재 시도를 수행하는 일반적이고 빠른 방법은 'GOTO'키워드를 사용하는 것이지만 이로 인해 논리와 코드가 엉망이 될 수 있습니다. 그래서 나는 'GOTO'를 사용하지 않으려 고 노력하고 있지만 재귀 접근 방식을 사용합니다.
논리 구현
먼저 'Abort', 'Retry'및 'Ignore'로직을 구현하는 데모 코드를 보여 드리겠습니다.
/// <summary>
/// This is the main function to do the work with retry logic
/// </summary>
/// <param name="jobName">Indicates current job name for displaying in message box</param>
/// <param name="retryCount">Indicates how many retried has been executed</param>
/// <returns>
/// -1: Abort is selected by user in message box
/// 0: Ignore is selected by user in message box or there is no error when doing current job
/// </returns>
private int StartWorkProcess(string jobName, int retryCount)
{
try
{
//do something here
Console.WriteLine("doing job " + jobName + "...");
//demo an exception when the job name's length equals to 3, 6 and 9
if (Math.IEEERemainder(jobName.Length, 3)==0)
{
throw new Exception();
}
}
catch
{
switch (MessageBox.Show("Failed doing job " + jobName, string.Empty, MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Error))
{
case System.Windows.Forms.DialogResult.Abort:
return -1; //Abort all
break;
case System.Windows.Forms.DialogResult.Retry:
if (retryCount > 10) //Limite the retry times
{
switch (MessageBox.Show("Too many retries! Yes to abort the whole job, No to ignore current task.", string.Empty, MessageBoxButtons.YesNo, MessageBoxIcon.Warning))
{
case System.Windows.Forms.DialogResult.Yes:
return -1; //Abort all
break;
case System.Windows.Forms.DialogResult.No:
//do nothing more
return 0;
break;
}
}
else
{
return StartWorkProcess(jobName, retryCount + 1);
}
break;
case System.Windows.Forms.DialogResult.Ignore:
//do nothing more
break;
}
}
return 0;
}
이것은 '중단', '재시도'및 '무시'로직으로 작업을 수행하는 주요 방법입니다.
다음은 몇 가지 핵심 사항입니다.
- try… catch 블록을 사용하여 예외를 포착합니다. 물론 특정 예외를 지정하기 위해이를 여러 캐치로 확장 할 수 있습니다.
- 예외가 있고 사용자가 재 시도를 선택하면이 메서드는 retryCount를 늘리고 자신을 다시 호출하여 재 시도에 대해 동일한 논리를 다시 실행합니다.
- 상태를 표시하고 호출자 함수가 자체 작업을 수행하려면 반환 값이 필요합니다.
- 재시도 횟수도 추적해야하며 재시도 횟수가 임계 값을 초과하면 현재 작업을 강제로 중단하거나 무시해야합니다. 이는 잠재적 인 메모리 부족 및 스택 오버플로 문제를 방지 할 수 있습니다.
그리고 다음은 작업 메서드의 반환 값을 사용할 호출자 함수입니다.
/// <summary>
/// On OK button click, it will call the work function to do the job.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnOK_Click(object sender, EventArgs e)
{
string job = string.Empty;
//Simulate 9 jobs with job name 1, 12, 123, 1234 and etc.
for (int i = 1; i < 10; i++)
{
job = job + i.ToString();
if (StartWorkProcess(job, 0) == -1)
{
break;
}
}
}
코드를 실행할 때 Visual Studio 출력 창의 프로그램 출력을 통해 결과를 모니터링 할 수 있습니다. 다음은 샘플 출력입니다.
doing job 1...
doing job 12...
doing job 123...
A first chance exception of type 'System.Exception' occurred in RetryIgnoreInRecursion.exe
doing job 123...
doing job 123...
A first chance exception of type 'System.Exception' occurred in RetryIgnoreInRecursion.exe
A first chance exception of type 'System.Exception' occurred in RetryIgnoreInRecursion.exe
doing job 1234...
doing job 12345...
doing job 123456...
doing job 1234567...
doing job 12345678...
doing job 123456789...
이제 더 나은 일을하십시오
이제 내가 말하는 내용과 논리가 코드에서 어떻게 구현되는지에 대한 기본적인 아이디어가 있어야합니다. 그러나 템플릿 메소드 패턴을 사용하여 코드를 재사용 가능하게 만드는 더 나은 작업을 수행해 보겠습니다.
추상 클래스가 생성되고 기본 재시도 / 무시 / 중단 논리가 구현되는 반면 실제 작동 논리는 구현되지 않고 추상 메서드로 하위 클래스에 남겨집니다.
abstract class RetryIgnoreHandlerBase
{
/// <summary>
/// Abstract method for subclass to implement actual working logic
/// </summary>
protected abstract void DoActualJob(string jobName);
/// <summary>
/// This is the main function to do the work with retry logic
/// </summary>
/// <param name="jobName">Indicates current job name for displaying in message box</param>
/// <param name="retryCount">Indicates how many retried has been executed</param>
/// <returns>
/// -1: Abort is selected by user in message box
/// 0: Ignore is selected by user in message box or there is no error when doing current job
/// </returns>
public int StartWorkProcess(string jobName, int retryCount)
{
try
{
DoActualJob(jobName);
}
catch
{
switch (MessageBox.Show("Failed doing job " + jobName, string.Empty, MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Error))
{
case System.Windows.Forms.DialogResult.Abort:
return -1; //Abort all
break;
case System.Windows.Forms.DialogResult.Retry:
if (retryCount > 10) //Limite the retry times
{
switch (MessageBox.Show("Too many retries! Yes to abort the whole job, No to ignore current task.", string.Empty, MessageBoxButtons.YesNo, MessageBoxIcon.Warning))
{
case System.Windows.Forms.DialogResult.Yes:
return -1; //Abort all
break;
case System.Windows.Forms.DialogResult.No:
//do nothing more
return 0;
break;
}
}
else
{
return StartWorkProcess(jobName, retryCount + 1);
}
break;
case System.Windows.Forms.DialogResult.Ignore:
//do nothing more
break;
}
}
return 0;
}
}
하위 클래스는 위의 추상 클래스를 상속하고 대신 실제 작동 논리를 구현합니다.
class DemoRetry: RetryIgnoreHandlerBase
{
protected override void DoActualJob(string jobName)
{
//do something here
Console.WriteLine("doing job " + jobName + "...");
//demo an exception when the job name's length equals to 3, 6 and 9
if (Math.IEEERemainder(jobName.Length, 3) == 0)
{
throw new Exception();
}
}
}
그런 다음 호출자 함수에 대한 관련 변경 :
private void btnOK_Click(object sender, EventArgs e)
{
string job = string.Empty;
DemoRetry demo = new DemoRetry();
//Simulate 9 jobs with job name 1, 12, 123, 1234 and etc.
for (int i = 1; i < 10; i++)
{
job = job + i.ToString();
if (demo.StartWorkProcess(job, 0) == -1)
{
break;
}
}
}
'C#.Net' 카테고리의 다른 글
Windows 작업 스케줄 API (0) | 2020.12.08 |
---|---|
Windows 암호정책 확인하는 Class (0) | 2020.12.01 |
한글 형태소 분석 (0) | 2020.09.21 |
IE를 윈도우 탐색기 또는 InternetExplorer창에 띄우는 방법 컨트롤 (0) | 2020.02.27 |
C# Winform 프로그래밍에서 IE 띄우기 (0) | 2020.02.27 |