C# 개발에 도움을 주는 기본 개념 7가지

이 글에서는 모든 개발자가 반드시 알아야 할 다양한 C# 개념을 살펴봅니다. 코드 예제를 알고 이해한다면 .NET에서 꽤 잘하고 있는 것일 가능성이 높습니다.

1. IEnumerable<T>ICollection<T>의 차이점

C#으로 로직을 작성할 때 개발자는 IEnumerable<T>ICollection<T>를 자주 접하게 됩니다. 이 둘은 매우 비슷해 보이지만 소프트웨어 개발에서 서로 다른 용도로 사용됩니다.

  • IEnumerable<T>는 일반 컬렉션이 아닌 컬렉션의 기본 인터페이스 역할을 합니다. 정의된 유형의 컬렉션을 반복하는 데 도움이 됩니다.

데이터 조작이 허용되지 않으므로 더 안전한 경량 컬렉션을 사용하는 것이 좋습니다. 데이터 조작을 방지하려면 어떤 컬렉션이든 IEnumerable<T>을 사용하는 것이 좋습니다.

1
2
3
4
5
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>를 확장하여 변경 메서드를 사용하여 수정할 수 있습니다. 이 인터페이스는 컬렉션의 개수를 추가, 제거 및 확인하는 메서드로 구성됩니다.
1
2
3
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 메서드에 서비스를 등록합니다. 여기에서 주입할 수 있는 서비스를 정의합니다.
1
2
3
4
public void ConfigureServices(IServiceCollection services) {
// 서비스 등록
services.AddTransient<IMyService, MyService>();
}

생성자 주입을 통해 클래스에 서비스를 주입하세요. 이렇게 하면 클래스가 직접 생성할 필요 없이 종속성을 받을 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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. refout 매개변수의 차이점

C#에서 refout은 매개변수를 참조로 전달하는 데 사용되지만, 서로 다른 특징이 있습니다.

  • ref 매개변수는 메서드에 전달되기 전에 변수를 초기화해야 합니다. 그런 다음 메서드는 변수 값을 수정할 수 있습니다.
1
2
3
4
5
6
7
8
public void UpdateValue(ref int number)
{
number += 10;
}

int myNumber = 5;
UpdateValue(ref myNumber);
Console.WriteLine(myNumber); // Outputs: 15
  • out 매개변수는 전달되기 전에 초기화가 필요하지 않습니다. 이 메서드는 반환하기 전에 out 매개변수에 값을 할당해야 합니다.
1
2
3
4
5
6
7
8
9
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. asyncawait

.NET에서 비동기 프로그래밍은 부하가 걸린 상태에서도 잘 작동하는 효율적인 애플리케이션을 작성하는 데 필수적입니다. asyncawait 키워드는 비동기 작업을 간소화합니다.

  • async 메서드를 사용하면 작업을 비동기적으로 수행할 수 있습니다. 메서드에 async 키워드를 표시하면 그 안에 await을 사용할 수 있습니다.
1
2
3
4
5
public async Task<string> FetchDataAsync()
{
await Task.Delay(1000); // Simulates an asynchronous operation
return "Data fetched";
}
  • await은 메인 스레드를 차단하지 않아 애플리케이션 UI에 도움이 됩니다.
1
2
3
4
5
public async Task ShowDataAsync()
{
string data = await FetchDataAsync();
Console.WriteLine(data);
}

애플리케이션의 성능을 향상시키려면 asyncawait 기능을 효과적으로 사용하면서 동시에 애플리케이션 UI의 반응성을 유지하세요.

5. 예외 처리

예외를 원활하게 처리하는 것은 견고하고 사용자 친화적인 애플리케이션을 유지하는 데 매우 중요합니다. .NET Core는 예외 처리를 위한 다양한 메커니즘을 제공합니다.

  • Local 예외 처리: try-catch 블록을 사용하여 예외를 포착하고 처리합니다.
1
2
3
4
5
6
7
8
try
{
int result = 10 / 0; // DivideByZeroException을 던집니다.
}
catch (DivideByZeroException ex)
{
Console.WriteLine("오류가 발생했습니다: " + ex.Message);
}
  • Global 예외 처리는 미들웨어를 사용하여 관리할 수 있습니다. 모든 유형의 예외를 공통된 위치에서 잡으면 개발자가 사용자에게 친숙하고 일반적인 오류 메시지를 관리할 수 있습니다.
1
2
3
4
public void Configure(IApplicationBuilder app)
{
app.UseExceptionHandler("/Home/Error");
}

Global 예외 처리 미들웨어는 모든 애플리케이션 오류와 예외를 처리할 수 있는 공통된 장소를 제공합니다. 이를 통해 애플리케이션이 일관되게 응답을 처리할 수 있습니다.

6. ASP.NET Core에서 appsettings.json의 역할

appsettings.json 파일은 구성(configuration) 문자열 및 애플리케이션별 키와 같은 애플리케이션 자격 증명을 관리하는 데 사용됩니다. 구성 설정은 환경별로 나눌 수도 있습니다.

  • appsettings.json 파일 예시:
1
2
3
4
5
6
7
8
9
10
{
"ConnectionStrings": {
"DefaultConnection": "Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;"
},
"Logging": {
"LogLevel": {
"Default": "Warning"
}
}
}

애플리케이션의 구성 설정 값에 액세스하는 방법은 내장된 구성 시스템을 사용하면 간단합니다.

1
2
3
4
5
6
7
8
9
public class MyService
{
private readonly string _connectionString;

public MyService(IConfiguration configuration)
{
_connectionString = configuration.GetConnectionString("DefaultConnection");
}
}

appettings.json 파일을 사용하면 구성 설정을 쉽게 가져올 수 있으므로 효율적으로 처리해야 합니다.

7. C#에서 TaskThread 이해하기

TaskThread는 모두 C#에서 동시(concurrent) 프로그래밍에 사용되지만 서로 다른 용도로 사용됩니다.

  • Thread는 단일 실행 경로를 나타내며 하위 레벨 구조입니다. 실행에 대한 더 많은 제어 기능을 제공하지만 수동 관리가 필요합니다.
1
2
3
4
5
6
Thread thread = new Thread(() =>
{
Console.WriteLine("새 스레드에서 실행 중");
});

thread.Start();
  • Task는 비동기 연산을 구현하는 추상적인 기능을 제공하며 async/await과 함께 사용됩니다.
1
2
3
4
Task.Run(() =>
{
Console.WriteLine("비동기적으로 실행 중");
});

Task는 비동기 연산의 관리를 간소화하며 최신 C# 개발에서 선호되는 선택입니다.

Share