본문 바로가기

CSharp156

Memory<T>와 IMemoryOwner<T>로 고성능 버퍼 관리하기 Memory와 IMemoryOwner로 고성능 버퍼 관리하기 Memory와 IMemoryOwner는 배열을 안전하게 여러 곳에 공유하거나 슬라이스하며, 풀링(Buffer Pool)을 통해 대량 데이터를 고성능·저비용으로 처리할 수 있게 해주는 고급 메모리 관리 도구입니다. using System; using System.Buffers; // ArrayPool, IMemoryOwner 지원 class Program { static void Main() { // 1) 메모리 풀에서 버퍼 대여 IMemoryOwner owner = MemoryPool.Shared.Rent(16); // 2) Memory로 버퍼 구역 표현 Memory .. 2025. 11. 24.
List의 Find·FindAll로 원하는 데이터 빠르게 찾기 List의 Find·FindAll로 원하는 데이터 빠르게 찾기 Find와 FindAll은 리스트에서 조건에 맞는 단일 요소 또는 모든 요소를 간편하고 빠르게 검색할 수 있게 해주는 메서드로, 조건 탐색을 반복문보다 더 직관적이고 안전하게 구현할 수 있습니다. using System; using System.Collections.Generic; class Program { static void Main() { var names = new List { "Alex", "Brian", "Alice", "Bella", "David" }; // 1) Find: 조건에 맞는 "첫 번째" 요소 반환 string firstA = names.Find(name.. 2025. 11. 21.
if 대신 switch 표현식으로 더 깔끔한 조건식 만들기 if 대신 switch 표현식으로 더 깔끔한 조건식 만들기 switch 표현식은 여러 조건 분기를 간결한 식(Expression) 형태로 작성할 수 있게 해주어, 기존의 긴 if-else 체인을 더 읽기 쉽고 유지보수하기 좋은 형태로 바꿔주는 기능입니다. using System; class Program { static void Main() { int grade = 85; // switch 표현식으로 점수 → 등급 매핑 string level = grade switch { >= 90 => "A", >= 80 => "B", >= 70 => "C", .. 2025. 11. 20.
구조적 로깅(Structured Logging)과 ILogger<T> 활용하기 구조적 로깅(Structured Logging)과 ILogger 활용하기 구조적 로깅은 단순 문자열 로그가 아니라 이름 있는 필드와 값을 함께 기록해 머신 분석 가능한 형태로 데이터를 남기는 방식으로, 대규모 서비스의 성능 모니터링·문제 추적·관찰성 향상에 필수적인 기술입니다. using System; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; class Program { static void Main() { // DI 컨테이너 구성 및 로거 설정 var services = new ServiceCollection() .AddLo.. 2025. 11. 19.
ValueTuple로 여러 값을 간단하고 효율적으로 반환하기 ValueTuple로 여러 값을 간단하고 효율적으로 반환하기 ValueTuple은 함수에서 여러 값을 하나의 구조로 묶어 반환하기 위한 경량 구조체입니다. 클래스를 생성하거나 별도 DTO를 만들 필요 없이 가독성 좋은 이름 기반 반환값을 구성할 수 있습니다. 구조체(Value Type)이므로 참조 할당 비용이 없고 가벼움. Deconstruct(분해) 문법을 자연스럽게 지원해 사용성이 뛰어납니다. public static (int sum, double average) CalculateStats(int[] numbers) { int sum = numbers.Sum(); double avg = numbers.Average(); return (sum, avg); } // 사용 예시 v.. 2025. 11. 17.
Array.Exists / Array.Find / Array.FindAll로 배열 검색하기 Array.Exists / Array.Find / Array.FindAll로 배열 검색하기Array.Exists, Array.Find, Array.FindAll은 배열 내 특정 조건을 만족하는 요소를 람다식 조건으로 빠르게 검색할 수 있게 해주는 함수들로, 반복문을 직접 작성할 필요 없이 간결하고 오류 없는 배열 검색이 가능할 때 사용합니다. using System; class Program { static void Main() { int[] numbers = { 10, 25, 40, 55, 60, 75, 90 }; // 1) Array.Exists - 조건을 만족하는 요소가 존재하는지만 확인 bool hasLarge = Array.Exist.. 2025. 11. 14.
pattern matching으로 조건문을 더 간결하고 직관적으로 표현하기 pattern matching으로 조건문을 더 간결하고 직관적으로 표현하기 C#의 Pattern Matching(패턴 매칭) 은 is, switch, when 구문을 활용하여 값과 타입을 동시에 비교하는 기능입니다. 기존의 다중 if-else 문을 대체해 코드 가독성과 유지보수성을 높이며, 타입 검사와 조건 검사를 하나로 통합할 수 있습니다. C# 9 이후에는 논리 패턴, 관계 패턴, 조합 패턴까지 지원되어 훨씬 강력해졌습니다. string GetAccessLevel(object user) => user switch { Admin a when a.Level > 5 => "최고 관리자", Admin => "일반 관리자", Guest => "게스트 사용자", null => .. 2025. 11. 12.
ref와 out 키워드의 차이 이해하기 ref와 out 키워드의 차이 이해하기ref와 out은 메서드에 인수를 참조(Reference) 로 전달하여 호출자와 피호출자 간에 값을 공유할 수 있게 하지만, ref는 이미 초기화된 변수 전달, out은 메서드 내부에서 반드시 값을 할당해야 한다는 차이가 있습니다. using System; class Program { // 1️⃣ ref 매개변수: 이미 값이 있어야 함 static void AddTen(ref int number) { number += 10; } // 2️⃣ out 매개변수: 내부에서 반드시 초기화해야 함 static void GetRandomValue(out int value) { Random rnd.. 2025. 11. 11.
async streams로 비동기 데이터 스트림을 효율적으로 처리하기 async streams로 비동기 데이터 스트림을 효율적으로 처리하기 async streams는 IAsyncEnumerable 기반으로 비동기적으로 데이터를 순차적으로 생산·소비할 수 있는 기능입니다. 기존에는 비동기 데이터를 배열·리스트에 모두 담은 뒤 한 번에 반환했지만, async stream은 데이터가 도착하는 즉시 순차적으로 처리할 수 있습니다. 네트워크 스트림, 파일 읽기, 대용량 데이터 처리 같은 상황에서 메모리 절약 + 반응성 향상이 가능합니다. Before — 전체 데이터를 로드 후 처리 (메모리 사용량 증가) public async Task> LoadDataAsync() { await Task.Delay(1000); return Enumerable.Range(1, .. 2025. 11. 10.
Expression-bodied 멤버로 코드 간결하게 작성하기 Expression-bodied 멤버로 코드 간결하게 작성하기Expression-bodied 멤버는 메서드, 속성, 생성자 등을 한 줄 식으로 간결하게 표현할 수 있는 문법으로, 코드의 가독성과 유지보수성을 높여줍니다. using System; class Person { // 1️⃣ 필드 private string _name; // 2️⃣ 생성자 (Expression-bodied) public Person(string name) => _name = name; // 3️⃣ 속성 (Getter/Setter 간결화) public string Name { get => _name; // get 블록 축약 set => _.. 2025. 11. 7.
delegate(델리게이트)로 메서드를 변수처럼 다루기 delegate(델리게이트)로 메서드를 변수처럼 다루기delegate는 메서드의 참조(주소)를 저장하여 변수처럼 전달하거나 실행할 수 있게 해주는 타입 안전한 함수 포인터입니다. using System; class Program { // 1️⃣ 델리게이트 선언 delegate int MathOperation(int a, int b); // 2️⃣ 델리게이트에 연결할 메서드 static int Add(int x, int y) => x + y; static int Multiply(int x, int y) => x * y; static void Main() { // 3️⃣ 델리게이트 인스턴스 생성 MathOperation op =.. 2025. 11. 6.
string.Equals와 == 연산자의 차이 이해하기 string.Equals와 == 연산자의 차이 이해하기 C#에서 문자열 비교 시 == 연산자와 string.Equals()는 유사하지만, 비교 옵션(대소문자 구분, 문화권 설정 등) 에 따라 동작이 달라질 수 있어 올바른 비교 방식을 이해하는 것이 중요합니다. using System; using System.Globalization; class Program { static void Main() { string a = "Hello"; string b = "hello"; string c = "HELLO"; // 1️⃣ == 연산자 (기본: 대소문자 구분) Console.WriteLine(a == b); // False.. 2025. 11. 5.
Parallel.For와 PLINQ로 멀티스레드 데이터 처리하기 Parallel.For와 PLINQ로 멀티스레드 데이터 처리하기Parallel.For와 PLINQ는 반복문이나 LINQ 쿼리를 여러 스레드에서 동시에 실행하여 CPU 사용률을 극대화하고 대용량 데이터를 빠르게 처리할 수 있게 해주는 병렬 처리 기술입니다. using System; using System.Diagnostics; using System.Linq; using Systehttp://m.Threading.Tasks;class Program { static void Main() { int[] numbers = Enumerable.Range(1, 10_000_000).ToArray(); Stopwatch sw = new Stopwatch(); .. 2025. 11. 4.
ref struct로 스택 전용 구조체로 메모리 효율 극대화하기 ref struct로 스택 전용 구조체로 메모리 효율 극대화하기ref struct는 스택(stack) 에만 존재할 수 있는 구조체 타입으로, 힙 할당을 원천적으로 차단하여 메모리 효율과 성능 안정성을 높이는 기능입니다. 일반 struct는 복사 시 비용이 크거나 힙에 올려질 수 있지만, ref struct는 GC 영향이 전혀 없습니다. 대표적인 예로 Span와 ReadOnlySpan가 있습니다 — 모두 ref struct 기반으로 구현되어 있습니다. 민감한 데이터(예: 암호, 토큰)를 힙에 남기지 않기 때문에 보안성도 향상됩니다. ref struct StackBuffer { private Span _data; public StackBuffer(Span data) { .. 2025. 11. 3.
Lazy<T>로 지연 초기화(Lazy Initialization) 구현하기 Lazy로 지연 초기화(Lazy Initialization) 구현하기 C#의 Lazy는 객체를 실제로 필요할 때까지 생성하지 않고 지연시키는 클래스로, 프로그램 시작 시 모든 객체를 한꺼번에 만들지 않고 처음 접근할 때 생성되도록 합니다. 이 기능은 메모리 사용을 줄이고, 불필요한 초기화를 피하며, 특히 무거운 리소스(DB 연결, 파일 로딩 등) 를 다루는 상황에서 성능 최적화에 매우 유용합니다. 또한 Lazy는 스레드 안전(Thread-safe) 하게 동작하여 멀티스레드 환경에서도 안정적으로 사용할 수 있습니다. using System; class ExpensiveResource { public ExpensiveResource() { Console.WriteLi.. 2025. 10. 31.
switch expression으로 깔끔한 조건문 작성하기 switch expression으로 깔끔한 조건문 작성하기 **switch expression**은 기존 switch 문을 간결하고 함수형 스타일로 개선한 문법입니다. 코드가 짧아지고, 조건별 반환값 처리가 깔끔해지며, 특히 패턴 매칭(Pattern Matching) 과 함께 사용하면 가독성이 대폭 향상됩니다. 무엇: 기존 switch 문의 축약형 표현식 버전 왜: 여러 조건에 따라 다른 값을 반환할 때 코드 중복과 가독성 저하를 줄이기 위해 언제: 여러 조건별 반환값 결정 로직이 있을 때 if-else 블록이 너무 길어질 때 💡 기존 switch가 “흐름 제어용”이라면, switch expression은 “값 계산용”입니다. using System; class Program { static v.. 2025. 10. 30.
required 멤버로 안전하고 명확한 객체 초기화하기 required 멤버로 안전하고 명확한 객체 초기화하기 required 키워드는 클래스나 구조체의 특정 속성이 반드시 초기화되어야 함을 강제합니다. 이는 컴파일 타임에서 누락된 필드를 감지하여 런타임 NullReferenceException을 예방합니다. DTO, 설정 객체, 데이터 전달용 클래스 등에서 데이터 불완전성을 막는 데 유용합니다. 기존의 생성자 강제 방식보다 유연하며, 객체 이니셜라이저(Object Initializer) 와 함께 안전하게 사용됩니다. public class User { public required string Name { get; set; } public required string Email { get; set; } } // 모든 required 속성.. 2025. 10. 29.
문자열 보간기(Interpolated String Handler)로 포매팅 성능 최적화하기 문자열 보간기(Interpolated String Handler)로 포매팅 성능 최적화하기 C# 10부터 Interpolated String Handler 기능이 도입되어, 문자열 보간($"...")을 사용할 때 불필요한 문자열 생성 및 메모리 할당을 최소화할 수 있습니다. 기존의 string.Format()이나 단순 보간식은 모든 문자열을 미리 결합하기 때문에 성능이 저하될 수 있었지만, 이 기능은 필요할 때만 문자열을 생성하여 메모리 효율과 속도를 동시에 확보합니다. 특히 로깅, 디버깅, 조건부 문자열 구성 시 불필요한 연산을 방지하여 CPU 사용량과 GC 부담을 줄이는 데 효과적입니다. Before (일반 문자열 보간) using System; class Program { static.. 2025. 10. 28.
foreach vs for — 성능과 사용 목적 비교 foreach vs for — 성능과 사용 목적 비교C#에서 컬렉션을 순회할 때 자주 사용하는 반복문은 **for**와 **foreach**입니다. 두 문법은 비슷해 보이지만, 메모리 사용 방식과 성능, 코드 목적이 다릅니다. 데이터를 순회(iteration)하는 두 가지 방식. 상황에 따라 더 빠르고 안전한 코드를 작성하기 위해 인덱스 접근이 필요한 경우엔 for, 단순 순회엔 foreach를 사용합니다. for는 인덱스를 직접 제어하지만, foreach는 안전하고 간결합니다. using System; using System.Diagnostics; class Program { static void Main() { int[] numbers = new int[1_000_000].. 2025. 10. 24.
record struct로 불변 값 타입(Value Type) 안전하게 설계하기 record struct로 불변 값 타입(Value Type) 안전하게 설계하기record struct는 **값 타입(value type)**으로 작동하는 불변(immutable) 데이터 컨테이너입니다. 일반 struct는 복사 기반이라 값 변경 시 버그가 발생하기 쉽지만, record struct는 불변 + 비교 연산 최적화를 제공합니다. 주로 좌표, 설정, 파라미터, DTO 등 변경이 불필요한 데이터에 적합합니다. record class와 달리 힙 할당이 아닌 스택 기반이라 GC 부담이 적습니다. using System; public readonly record struct Point(int X, int Y) { public double Distance => Math.Sqrt(X * X +.. 2025. 10. 22.