고급 C# 기능 정리: 열거형, 해체, 변환, 컬렉션 및 멀티스레딩

플래그를 사용한 복합 열거형 구성

특성 [Flags]를 적용하면 열거형 값이 비트 단위로 조합 가능해집니다. 이는 권한 또는 상태를 다중 조합으로 표현할 때 유용합니다.

[Flags]
public enum Permissions
{
    Read = 1,
    Write = 2,
    Execute = 4,
    Admin = Read | Write | Execute
}

다음과 같이 여러 값을 결합하여 사용할 수 있습니다:

var userPermissions = Permissions.Write | Permissions.Read;
Console.WriteLine(userPermissions); // 출력: Read, Write

if (userPermissions.HasFlag(Permissions.Read))
{
    Console.WriteLine("읽기 권한 있음");
}

객체 해체 (Deconstruct) 기능 활용

Deconstruct 메서드를 통해 객체에서 특정 필드를 직접 추출할 수 있습니다. 이는 구조 분해 할당과 함께 사용됩니다.

public class Order
{
    public DateTime CreatedAt { get; set; }
    public string Code { get; set; }

    public void Deconstruct(out DateTime createdAt, out string code)
    {
        createdAt = CreatedAt;
        code = Code;
    }
}

// 사용 예시
var order = new Order(DateTime.Now, "ORD-001");
(var date, var id) = order;
Console.WriteLine($"생성일: {date:yyyy-MM-dd}, 주문번호: {id}");

암시적 및 명시적 변환 연산자

사용자 정의 타입 간의 자동 변환을 정의할 수 있습니다.

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class Student
{
    public string FullName { get; set; }

    public static implicit operator Student(Person person)
    {
        return new Student { FullName = $"{person.FirstName} {person.LastName}" };
    }

    public static explicit operator Person(Student student)
    {
        return new Person { FirstName = student.FullName };
    }
}

// 사용
var person = new Person { FirstName = "홍", LastName = "길동" };
Student student = person;                    // 암시적 변환
Person person2 = (Person)student;             // 명시적 변환

반복 가능한 컬렉션 처리: IEnumerable과 yield 반환

IEnumerable 인터페이스는 반복 가능한 컬렉션을 정의하며, yield return은 지연 평가를 지원합니다.

public IEnumerable<string> GetEmployeeNames()
{
    yield return "김철수";
    yield return "박영희";
    yield break; // 조건에 따라 종료
}

// 사용
var names = GetEmployeeNames().ToList();
Console.WriteLine(string.Join(", ", names));

DateTime, DateTimeOffset, TimeSpan 차이점

  • DateTime: 로컬 시간대 기준, 시간 정보 포함.
  • DateTimeOffset: UTC와의 오프셋을 명시적으로 저장, 국제화 시 유용.
  • TimeSpan: 시간 간격을 표현, 두 시점 사이의 차이 계산.

이벤트 처리 방식 비교

기본적인 델리게이트 기반 이벤트와 이벤트 매개변수를 사용하는 고급 방식을 비교합니다.

// 기본 이벤트 선언
public delegate bool OrderEventHandler(string orderCode);
public event OrderEventHandler OrderCreated;

// 이벤트 매개변수 사용
public class PaymentSucceededArgs : EventArgs
{
    public string OrderId { get; set; }
    public PaymentSucceededArgs(string orderId) => OrderId = orderId;
}

public event EventHandler<PaymentSucceededArgs> PaymentCompleted;

익명 타입 활용

임시 데이터 구조를 빠르게 생성할 수 있습니다.

var address = new { Street = "제주로 123", City = "서귀포" };
Console.WriteLine(address.Street); // 제주로 123

LINQ의 into 키워드 및 그룹화 후 전개

intojoin 후 그룹화된 결과를 임시 변수로 저장하고, 이후 from 문에서 전개할 수 있게 합니다.

var query = from customer in customers
            join purchase in purchases.Where(p => p.Price > 5000)
            on customer.Id equals purchase.CustomerId
            into customerPurchases
            from cp in customerPurchases.DefaultIfEmpty()
            select new
            {
                Name = customer.Name,
                Price = cp?.Price,
                Product = cp?.Name
            };

멀티스레딩에서 volatile 키워드의 역할

volatile는 공유 변수의 값이 캐시되지 않도록 보장하며, 모든 스레드가 메모리에서 직접 읽고 쓰도록 합니다. 단, 원자성 연산이나 잠금 없이도 동작하지 않습니다.

private volatile bool _isRunning = true;

// 스레드에서 읽기
while (_isRunning)
{
    // 작업 수행
}

프로그램 세부 정보 설정: AssemblyDescriptionAttribute

어셈블리에 설명을 추가할 수 있습니다.

[assembly: AssemblyDescription("이 어셈블리는 사용자 관리 시스템입니다.")]

MemoryCache 설정 및 최적화

ASP.NET Core에서 IMemoryCache를 설정할 때 다양한 옵션을 조정할 수 있습니다.

services.AddMemoryCache(options =>
{
    options.SizeLimit = 100;                   // 최대 항목 수 (상대적)
    options.CompactionPercentage = 0.1;        // 초과 시 압축 비율
    options.ExpirationScanFrequency = TimeSpan.FromSeconds(3); // 스캔 주기
});

공유 리소스 제어: SemaphoreSlim

비동기 환경에서 동시 접근을 제어하기 위한 경량 락입니다.

static readonly SemaphoreSlim _semaphore = new(1);

await _semaphore.WaitAsync();
try
{
    // 공유 리소스 접근
}
finally
{
    _semaphore.Release();
}

반사 기술: MakeGenericType 활용

런타임에 제네릭 타입을 동적으로 생성할 수 있습니다.

Type genericInterface = typeof(IAnmail<>).MakeGenericType(typeof(string));
object instance = Activator.CreateInstance(typeof(Lion));
var method = genericInterface.GetMethod("GetName");
var result = method.Invoke(instance, null);
Console.WriteLine(result); // "사자"

태그: C# Enumeration deconstruct conversion IEnumerable

7월 12일 01:21에 게시됨