1. 비동기 실행 흐름 제어 (async / await)
비동기 I/O 작업을 처리할 때 스레드를 차단하지 않고 대기 상태를 관리하는 패턴입니다. 작업이 외부 리소스(네트워크, 디스크 등)를 기다리는 동안 호출 스레드를 해제하여 시스템 처리량을 향상시킵니다. 작업 완료 시점이 되면 대기 상태의 태스크를 재개합니다.
public async Task FetchReportAsync()
{
var client = new HttpClient();
var response = await client.GetAsync("https://api.data.io/report");
// 네트워크 대기 중 메인 스레드는 다른 작업 수행 가능
var metrics = await response.Content.ReadAsStringAsync();
AnalyzeData(metrics);
}2. 객체 및 컬렉션 초기화 구문
인스턴스 생성과 속성 할당을 단일 표현식으로 결합하여 코드를 간결하게 만듭니다. 생성자 매개변수 순서에 의존하지 않고 명확한 명명 기반 초기화가 가능하며, 중첩된 데이터 구조를 직관적으로 구성할 때 유용합니다.
public class Device
{
public string Model { get; set; }
public int SerialNumber { get; set; }
}
var fleet = new List<Device>
{
new Device { Model = "Router-X1", SerialNumber = 8842 },
new Device { Model = "Switch-Y2", SerialNumber = 9915 }
};3. 람다식, 대리자 및 클로저
익명 함수를 인라인으로 정의하여 LINQ 쿼리나 이벤트 핸들러에서 로직을 직접 전달합니다. 외부 스코프의 변수를 캡처하는 클로저 특성을 활용하면 상태 공유가 용이해지며, 함수형 프로그래밍 패턴을 C#에 자연스럽게 적용할 수 있습니다.
int baseThreshold = 50;
var readings = new List<int> { 12, 65, 43, 88, 51 };
// 외부 변수 캡처 및 필터링
var activeSensors = readings.Where(r => r > baseThreshold).ToArray();
// 대리자 인스턴스화
Func<double, double> transform = val => val * Math.PI;
var result = transform(2.0);4. Null 병합 연산자 (??)
좌측 피연산자가 null이 아니면 해당 값을 반환하고, null일 경우 우측의 대체 값을 즉시 제공합니다. 구성 값 폴백 처리 체이닝 및 Nullable<T> 타입의 안전한 기본값 변환에 효과적입니다.
string fallbackRegion = config.Region ?? defaultSettings.Region ?? "us-east-1";
int? optionalPort = serverConfig.Port;
int activePort = optionalPort ?? 8080; // null 시 8080 할당5. 문자열 보간 ($)
문자열 리터럴 내부에 변수나 수식을 직접 삽입하여 가독성을 높이는 구문입니다. 중괄호 내에서 포맷팅 지정자나 조건 연산을 바로 실행할 수 있어 복잡한 String.Format 구문을 대체합니다.
decimal unitPrice = 24.50m;
int items = 5;
var summary = $"합계: {unitPrice * items:F2} 원 (처리시각: {DateTime.Now:HH:mm:ss})";6. Null 조건부 탐색 연산자 (?.)
객체 그래프를 순회할 때 중간 노드가 null인 경우 예외 발생 대신 전체 체인을 null로 안전하게 평가합니다. 방어적 코드 작성을 대폭 줄이고 런타임 안정성을 높입니다.
var targetCity = shipment?.Recipient?.Address?.City;
// shipment 또는 하위 속성이 null이어도 NullReferenceException 미발생7. nameof 연산자
심볼 이름을 컴파일 타임 문자열로 변환합니다. 매개변수 검증, 로깅, 특성(Attribute) 정의 시 하드코딩된 문자열 대신 사용하면 IDE 리팩토링 도구와 연동되어 이름 변경 시 자동으로 동기화됩니다.
public void RegisterAccount(string userId)
{
if (string.IsNullOrWhiteSpace(userId))
throw new ArgumentException($"'{nameof(userId)}' 값은 필수입니다.");
}8. 자동 구현 프로퍼티 초기화
프로퍼티 선언 시점에서 기본값을 할당하여 생성자 로직을 단순화합니다. setter를 제거하면 불변(immutable) 상태 필드를 쉽게 구성할 수 있으며, 읽기 전용 데이터 모델 설계에 적합합니다.
public class AuthToken
{
public string TokenValue { get; } = Guid.NewGuid().ToString();
public DateTime IssuedAt { get; set; } = DateTime.UtcNow;
}9. 타입 확인 및 안전 캐스트 (is / as)
is는 런타임 타입 일치 여부를 검사하며 패턴 매칭과 결합해 변수 선언을 동시에 처리합니다. as는 참조 형식을 안전하게 변환하며 실패 시 null을 반환하여 명시적 형변환 예외를 방지합니다.
object payload = LoadMessage();
if (payload is JsonMessage msg)
{
Console.WriteLine(msg.Body);
}
var xmlMsg = payload as XmlMessage;
if (xmlMsg is not null)
{
xmlMsg.Validate();
}10. 지연 실행 반복기 (yield)
yield return을 사용하여 컬렉션을 메모리에 모두 로드하지 않고 요청 시점마다 요소를 생성합니다. 대용량 데이터 스트리밍이나 무한 수열 처리 시 메모리 사용을 최소화하고 열거를 중간에 차단할 수 있습니다.
public static IEnumerable<int> EvenSequence(int count)
{
for (int i = 0; i < count; i++)
{
yield return i * 2;
}
}
// 호출 측에서 foreach 루프를 중단하면 생성도 즉시 멈춤