개발을 하다 보면 어떻게 예외 처리를 해야 하나 고민하게 된다. 조건문(if)으로 처리할지, 예외(Exception)를 던질지 선택 해야 하는 순간이 항상 있다.
어느 상황에서 조건문을 사용할 지, 혹은 예외를 사용할 지 알아보자.
1.조건문과 예외의 역할 차이
- 조건문(Validation / Guard Clause)
- 예상 가능한 시나리오에서 분기 처리
- 정상적인 흐름에 해당(비즈니스 로직에서의 예외)
- ex) 로그인 Validation 실패
- 예외(Exception)
- 예상하기 힘들거나 복구가 불가능한 상황
- 시스템 오류, 인프라 장애 같은 비정상적인 흐름
- ex) DB연결 실패, 네트워크 통신 불가, 파일이 손상되어 파일 파싱 불가
2. 예시
- 조건문
public bool Login(string id, string password)
{
if (id != "MyID")
{
return false;
}
if (password != "MyPassword")
{
return false;
}
return true;
}
- 아이디, 비밀번호의 검증은 예측이 가능한 상황이므로 if 조건문으로 처리
- 예외
public string ReadFileContent(string path)
{
try
{
return File.ReadAllText(path);
}
catch(IOException ex)
{
// 파일 시스템 자체 문제(디스크 오류 등)
throw new ApplicationException("File access failed.", ex);
}
}
- 파일을 읽는 과정에서 비정상적 오류 발생으로 예외 처리
예외처리 시 예외를 타입별로 나눌 때 범위가 가장 큰 예외를 마지막으로 작성해야 한다는 것을 주의해야 함.
public void ProcessFile(string path)
{
try
{
// 잠재적으로 예외가 발생할 수 있는 코드
var fileContent = File.ReadAllText(path);
ProcessContent(fileContent);
}
catch (FileNotFoundException ex) // 더 구체적인(파생된) 예외
{
// FileNotFoundException에 대한 복구 로직
Logger.LogError($"파일을 찾을 수 없습니다: {ex.Message}");
CreateDefaultFile(path);
}
catch (IOException ex) // 덜 구체적인 예외
{
// IOException에 대한 복구 로직
Logger.LogError($"파일 IO 오류: {ex.Message}");
NotifyAdmin("파일 접근 문제가 발생했습니다.");
}
catch (Exception ex) // 가장 기본적인 예외 (항상 마지막에 위치)
{
// 일반적인 예외에 대한 복구 로직
Logger.LogError($"예상치 못한 오류: {ex.Message}");
throw; // 복구할 수 없는 경우 다시 throw하여 상위 호출자에게 전파
}
}
또한, 복구할 수 없는 예외일 경우 상위 예외를 전달한다.
public class DataService
{
public void SaveData(Data data)
{
// 이 메서드는 데이터베이스 연결 실패와 같은 심각한 오류를 처리하지 않음
// 대신 상위 호출자에게 전파하여 처리하도록 함
_repository.Save(data); // 예외가 발생하면 그대로 전파됨
}
}
public class ApiController
{
private readonly DataService _dataService;
public IActionResult SaveData(DataDto dto)
{
try
{
var data = _mapper.Map<Data>(dto);
_dataService.SaveData(data); // 여기서 예외가 발생할 수 있음
return Ok("데이터가 성공적으로 저장되었습니다.");
}
catch (DbConnectionException ex)
{
// API 계층에서 데이터베이스 연결 오류 처리
_logger.LogError(ex, "데이터베이스 연결 오류");
return StatusCode(503, "서비스를 일시적으로 사용할 수 없습니다.");
}
catch (Exception ex)
{
_logger.LogError(ex, "데이터 저장 중 예상치 못한 오류");
return StatusCode(500, "내부 서버 오류");
}
}
}
예외/제어 코드 작성 시 위 사항을 유의하여 작성하니 코드가 굉장히 간결해지고 가독성이 높아짐을 느꼈다.
'C#' 카테고리의 다른 글
[C#] 비동기 프로그래밍 가이드(Async and Await) (0) | 2024.12.21 |
---|---|
[C#] Byte 크기로 문자열 길이 제한하기 (0) | 2024.08.29 |
[C#] IOException: Sharing violation on path 에러 해결 (0) | 2024.08.22 |
[C#] InstallUtil.exe로 Windows Service 설치 시 에러 (0) | 2023.12.22 |
[C#,MSSQL] The timeout period elapsed prior to obtaining a connection from the pool 에러 해결 (1) | 2023.11.19 |