이 글에서는 모든 개발자가 반드시 알아야 할 다양한 C# 개념을 살펴봅니다. 코드 예제를 알고 이해한다면 .NET에서 꽤 잘하고 있는 것일 가능성이 높습니다.
1. IEnumerable<T>
와 ICollection<T>
의 차이점
C#으로 로직을 작성할 때 개발자는 IEnumerable<T>
와 ICollection<T>
를 자주 접하게 됩니다. 이 둘은 매우 비슷해 보이지만 소프트웨어 개발에서 서로 다른 용도로 사용됩니다.
IEnumerable<T>
는 일반 컬렉션이 아닌 컬렉션의 기본 인터페이스 역할을 합니다. 정의된 유형의 컬렉션을 반복하는 데 도움이 됩니다.
데이터 조작이 허용되지 않으므로 더 안전한 경량 컬렉션을 사용하는 것이 좋습니다. 데이터 조작을 방지하려면 어떤 컬렉션이든 IEnumerable<T>
을 사용하는 것이 좋습니다.
IEnumerable<int> numbers = new List<int> { 1, 2, 3 };
foreach (var number in numbers) {
Console.WriteLine(number); // Outputs: 1 2 3
}
ICollection<T>
는IEnumerable<T>
를 확장하여 변경 메서드를 사용하여 수정할 수 있습니다. 이 인터페이스는 컬렉션의 개수를 추가, 제거 및 확인하는 메서드로 구성됩니다.
ICollection<int> data = new List<int> { 12, 34, 56 };
data.Add(4);
Console.WriteLine(data.Count); // Outputs: 4
컬렉션에 변경 메서드가 필요한 경우 ICollection<T>
, 간단한 읽기 작업에는 IEnumerable<T>
를 사용하는 것이 좋습니다.
2. .NET Core에서 종속성 주입의 역할
느슨하게 결합되고 테스트 가능한 코드를 작성하려는 경우, DI(Dependency Injection) 디자인 패턴을 사용하는 것을 권장합니다. .NET Core는 DI를 기본적으로 지원하므로 쉽게 구현할 수 있습니다.
Startup.cs
파일의ConfigureServices
메서드에 서비스를 등록합니다. 여기에서 주입할 수 있는 서비스를 정의합니다.
public void ConfigureServices(IServiceCollection services) {
// 서비스 등록
services.AddTransient<IMyService, MyService>();
}
생성자 주입을 통해 클래스에 서비스를 주입하세요. 이렇게 하면 클래스가 직접 생성할 필요 없이 종속성을 받을 수 있습니다.
public class MyController : Controller
{
private readonly IMyService _myService;
public MyController(IMyService myService)
{
_myService = myService;
}
public IActionResult Index()
{
var data = _myService.GetData();
return View(data);
}
}
개발자가 서비스 생성을 분리하면 코드의 유지 관리와 테스트가 더 쉬워집니다.
3. ref
와 out
매개변수의 차이점
C#에서 ref
와 out
은 매개변수를 참조로 전달하는 데 사용되지만, 서로 다른 특징이 있습니다.
ref
매개변수는 메서드에 전달되기 전에 변수를 초기화해야 합니다. 그런 다음 메서드는 변수 값을 수정할 수 있습니다.
public void UpdateValue(ref int number)
{
number += 10;
}
int myNumber = 5;
UpdateValue(ref myNumber);
Console.WriteLine(myNumber); // Outputs: 15
out
매개변수는 전달되기 전에 초기화가 필요하지 않습니다. 이 메서드는 반환하기 전에 out 매개변수에 값을 할당해야 합니다.
public void GetValues(out int value1, out int value2)
{
value1 = 10;
value2 = 20;
}
GetValues(out int a, out int b);
Console.WriteLine(a); // Outputs: 10
Console.WriteLine(b); // Outputs: 20
ref
는 일반적으로 메서드가 기존 변수를 수정해야 할 때 사용되며, out
은 메서드가 여러 값을 반환하거나 호출자가 제공하지 않은 값을 초기화해야 할 때 사용됩니다.
4. async
및 await
.NET에서 비동기 프로그래밍은 부하가 걸린 상태에서도 잘 작동하는 효율적인 애플리케이션을 작성하는 데 필수적입니다. async
및 await
키워드는 비동기 작업을 간소화합니다.
async
메서드를 사용하면 작업을 비동기적으로 수행할 수 있습니다. 메서드에async
키워드를 표시하면 그 안에await
을 사용할 수 있습니다.
public async Task<string> FetchDataAsync()
{
await Task.Delay(1000); // Simulates an asynchronous operation
return "Data fetched";
}
await
은 메인 스레드를 차단하지 않아 애플리케이션 UI에 도움이 됩니다.
public async Task ShowDataAsync()
{
string data = await FetchDataAsync();
Console.WriteLine(data);
}
애플리케이션의 성능을 향상시키려면 async
및 await
기능을 효과적으로 사용하면서 동시에 애플리케이션 UI의 반응성을 유지하세요.
5. 예외 처리
예외를 원활하게 처리하는 것은 견고하고 사용자 친화적인 애플리케이션을 유지하는 데 매우 중요합니다. .NET Core는 예외 처리를 위한 다양한 메커니즘을 제공합니다.
- Local 예외 처리: try-catch 블록을 사용하여 예외를 포착하고 처리합니다.
try
{
int result = 10 / 0; // DivideByZeroException을 던집니다.
}
catch (DivideByZeroException ex)
{
Console.WriteLine("오류가 발생했습니다: " + ex.Message);
}
- Global 예외 처리는 미들웨어를 사용하여 관리할 수 있습니다. 모든 유형의 예외를 공통된 위치에서 잡으면 개발자가 사용자에게 친숙하고 일반적인 오류 메시지를 관리할 수 있습니다.
public void Configure(IApplicationBuilder app)
{
app.UseExceptionHandler("/Home/Error");
}
Global 예외 처리 미들웨어는 모든 애플리케이션 오류와 예외를 처리할 수 있는 공통된 장소를 제공합니다. 이를 통해 애플리케이션이 일관되게 응답을 처리할 수 있습니다.
6. ASP.NET Core에서 appsettings.json
의 역할
appsettings.json
파일은 구성(configuration) 문자열 및 애플리케이션별 키와 같은 애플리케이션 자격 증명을 관리하는 데 사용됩니다. 구성 설정은 환경별로 나눌 수도 있습니다.
appsettings.json
파일 예시:
{
"ConnectionStrings": {
"DefaultConnection": "Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;"
},
"Logging": {
"LogLevel": {
"Default": "Warning"
}
}
}
애플리케이션의 구성 설정 값에 액세스하는 방법은 내장된 구성 시스템을 사용하면 간단합니다.
public class MyService
{
private readonly string _connectionString;
public MyService(IConfiguration configuration)
{
_connectionString = configuration.GetConnectionString("DefaultConnection");
}
}
appettings.json
파일을 사용하면 구성 설정을 쉽게 가져올 수 있으므로 효율적으로 처리해야 합니다.
7. C#에서 Task
와 Thread
이해하기
Task
와 Thread
는 모두 C#에서 동시(concurrent) 프로그래밍에 사용되지만 서로 다른 용도로 사용됩니다.
Thread
는 단일 실행 경로를 나타내며 하위 레벨 구조입니다. 실행에 대한 더 많은 제어 기능을 제공하지만 수동 관리가 필요합니다.
Thread thread = new Thread(() =>
{
Console.WriteLine("새 스레드에서 실행 중");
});
thread.Start();
Task
는 비동기 연산을 구현하는 추상적인 기능을 제공하며 async/await과 함께 사용됩니다.
Task.Run(() =>
{
Console.WriteLine("비동기적으로 실행 중");
});
Task
는 비동기 연산의 관리를 간소화하며 최신 C# 개발에서 선호되는 선택입니다.
'Language > C#' 카테고리의 다른 글
효율적인 .NET 개발을 위한 4가지 필수 라이브러리 소개 (0) | 2024.11.19 |
---|---|
[C#] LINQ 모범 사례 (0) | 2024.11.18 |
[C#] async, await 기능을 사용한 비동기 프로그래밍 (0) | 2024.10.21 |
.NET Core로 고성능 API 빌드하기 (0) | 2024.10.18 |
C#에서 DDD를 사용하는 것이 좋은 이유와 장단점 (0) | 2024.08.05 |
IT 기술과 개발 내용을 포스팅하는 블로그
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!