
C#은 마이크로소프트에서 개발한 객체 지향 프로그래밍 언어로, 닷넷(.NET) 런타임 위에서 실행되는 다양한 애플리케이션 개발에 쓰입니다. C#은 1999년에 .NET 개발과 함께 설계가 시작되어 2000년에 공식 발표/시연되었습니다.

자료형은 데이터가 '어떤 종류인지'를 컴퓨터에게 알려주는 규칙을 말합니다. 마치 상자에 어떤 종류의 물건을 넣을지 미리 정해두는 것과 같습니다. 자료형은 크게 값 형식(Value Type)과 참조 형식(Reference Type)으로 나뉩니다.

연산자는 값을 가지고 계산, 데이터 가공, 비교 등을 수행하는 기호입니다. 변수나 값에 대해 덧셈, 뺄셈 같은 계산을 하거나, 두 값이 같은지 비교하거나, 논리적인 판단을 내리는 등 다양한 작업을 수행할 수 있도록 도와줍니다.

코드를 쓰다 보면 '상황에 따라 다르게 처리'해야 하는 순간이 꼭 옵니다. 분기문을 사용하면 특정 조건에 따라 다른 코드를 실행하여 프로그램이 다양한 상황에서 유연하게 대응할 수 있게 합니다.

프로그래밍을 하다 보면 똑같은 작업을 여러 번 반복해야 할 때가 있습니다. 예를 들어, 1부터 100까지의 숫자를 출력하려면 WriteLine을 100번 사용해야 할까요? 이때 '반복문'이 등장합니다! 반복문은 작업 효율을 높여주는 아주 유용한 도구입니다.

프로그래밍을 하다 보면 같은 코드를 여러 번 작성하게 될 때가 있습니다. 필요할 때마다 코드를 반복해서 작성한다면 비효율적이고 코드가 길어집니다. 이럴 때 메서드(Method)를 사용하면 코드를 재사용할 수 있습니다.

메서드가 외부로부터 값을 받아 작업을 수행할 때 사용하는 것이 '매개변수'입니다. 마치 택배를 보낼 때 '선불', '착불', '반품 불가' 옵션을 붙이는 것과 비슷합니다. 이 값들을 통해 메서드는 유연하게 다양한 데이터를 처리할 수 있습니다.

'콘솔 계산기'는 텍스트 기반으로 동작하는 계산기 프로그램입니다. 지금까지 배운 내용을 복습하는 차원에서, '콘솔 계산기'를 만들어보려고 합니다.

프로그래밍을 하다 보면 코드에 설명을 달아야 할 순간이 꼭 생깁니다. 주석은 코드를 이해하고 유지보수하는 데 결정적인 역할을 하는 '설명서'입니다. 특히 협업할 때는 '이 코드가 왜 필요한지' 주석을 남겨 두는 게 중요하죠.

C#의 모든 변수는 고정된 데이터 형식(Type)을 가지고 있습니다. 예를 들어 int는 정수만 담을 수 있고, string은 문자열만 담을 수 있죠. 하지만 서로 다른 형식의 데이터를 함께 처리해야 할 때는 형변환(Type Conversion)이 필요합니다.

프로그래밍을 하다 보면 한정된 값 집합을 다루어야 할 때가 있습니다. 예를 들어, 요일(월~일), 상태(시작/진행/완료) 같은 경우가 그렇죠. 이런 상황에서는 열거형(Enum)을 사용해서 코드의 가독성과 안정성을 크게 높일 수 있습니다.

배열은 한마디로 "여러 개의 자료형을 순서대로 모아놓은 상자"라고 할 수 있어요. 예를 들어 50명의 시험 점수를 관리한다고 할 때, 50개의 변수를 만들어서 관리 한다면 너무 비효율적이겠죠? 이럴 때 배열을 사용하면 코드가 훨씬 간결하고 깔끔해집니다.

객체 지향 프로그래밍(Object-Oriented Programming, OOP)은 한마디로 현실 세계를 '객체(Object)'로 옮겨오는 사고방식입니다. 자동차, 사람, 강아지 등 이 객체들은 저마다 고유한 속성(데이터)과 행동(기능)을 가지고 있어요.

지난 글에서는 캡슐화, 상속, 다형성, 추상화를 통해서 OOP이라는 거대한 산의 지도를 펼쳐보았습니다. 이제 직접 등반 장비를 챙겨 클래스로 그 산을 오를 시간입니다. 이번 글에서는 객체를 만들어 내는 설계도, 클래스가 무엇인지, 어떻게 사용하는지 알아보겠습니다.

클래스 안에 정의된 멤버들은 크게 두 가지 방식으로 존재합니다. 바로 '정적(Static) 멤버'와 '인스턴스(Instance) 멤버'인데요, 이 둘의 차이를 명확히 이해하는 것이 객체 지향 프로그래밍에서 중요합니다!

정적 멤버를 다루다 보면 이런 궁금증이 생길 수 있습니다. "정적 멤버는 어떻게 초기화하나요?" "클래스의 모든 멤버를 정적으로만 가지고 있다면, 다룰 방법이 없을까요?" 이 질문들에 대한 해답은 '정적 생성자'와 '정적 클래스'에 있습니다.

객체의 복사 방식을 이해하지 못하면 나중에 데이터를 수정했는데, 원본 객체의 값까지 바뀌는 버그가 생길 수 있습니다. 이번 글에서는 객체를 복사하는 방법, 얕은 복사(Shallow Copy)와 깊은 복사(Deep Copy)의 차이점에 대해 파헤쳐 보겠습니다.

메서드의 매개변수 이름과 클래스의 필드 이름이 같을 때 컴퓨터는 어떻게 구분할까요? 이럴 때 등장하는 주인공은 팔색조 배우, this 키워드입니다. 또한 생성자를 여러 개 만들 때 중복되는 코드를 줄이기 위해 this()를 활용한 생성자 체이닝을 사용하기도 합니다.

상속은 이름 그대로, 부모 클래스의 속성(필드, 프로퍼티)과 기능(메서드)을 자식 클래스가 물려받아 사용할 수 있는 기능입니다. 이렇게 하면 자식 클래스들은 자신만의 고유한 기능을 추가하기만 하면 됩니다. 코드의 재사용성이 극대화되고, 유지보수가 매우 편리해지죠.

C# 코드가 길어져서 스크롤 압박을 느끼신 적은 없으신가요? 처음엔 편할지 몰라도 나중엔 원하는 클래스를 찾기조차 힘들어집니다. 이번 글에서는 비대해진 코드를 클래스 단위로 .cs 파일을 분리해서, 프로젝트를 깔끔하고 체계적으로 정리하는 방법에 대해 알아보겠습니다.

접근 제한자는 클래스에 접근할 수 있는 권한의 범위를 결정합니다. 마치 집 안의 모든 방을 손님에게 공개하지 않고, 안방은 가족만, 금고는 나만 들어갈 수 있게 방문을 잠그는 것과 같죠. 중요한 건 숨기고 필요한 것만 외부에 공개해서 코드의 안정성을 높여줍니다.

다형성이라는 단어는 Poly(많은) + Morph(형태)가 합쳐진 말로, 글자 그대로 많은 형태를 가질 수 있는 능력을 의미합니다. 한마디로 하나의 이름으로 여러 가지 동작을 실행하는 능력입니다. 객체가 무엇이냐에 따라 다른 행동을 하는 것이 다형성의 핵심입니다.

때로는 상속 관계에 더 세밀한 제어가 필요할 때가 있습니다. "부모님 메서드랑 이름은 같지만, 새로운 기능을 만들고 싶어요!" "내가 힘들게 완성한 메서드를 내 자식들이 절대 바꾸면 안 돼!" 이런 고민을 해결해 주는 new와 sealed에 대해 알아보겠습니다.

코드를 작성하다 보면 "이 클래스는 오직 저 클래스 안에서만 쓰이는데, 별도 파일로 분리해야 하나?" 하는 생각이 들 때가 있습니다. 마치 중요한 서류에 필요한 자료를 스테이플러로 함께 묶어두고 싶은 마음처럼요. 이럴 때 사용할 수 있는 기능이 중첩 클래스입니다.

혹시 C#을 사용하시다가 이런 생각해 보신 적 없나요? "string클래스에 단어 수를 세는 메서드가 있었으면..." 하지만 C#에서 string이나 int 처럼 이미 정의된 기능은 우리가 마음대로 수정할 수 없습니다. 이럴 때 필요한 기능이 바로 확장 메서드입니다!

'형변환'은 다형성을 구현하여 코드를 더 유연하고 재사용성을 높일 수 있죠. 하지만 잘못 사용하면 예기치 않은 오류를 만날 수도 있는 '양날의 검'과 같습니다. 이번 글에서는 어떻게 하면 안전하게 형변환을 할 수 있는지 is와 as키워드를 통해 살펴보겠습니다!

사용자의 사소한 실수 하나 때문에 프로그램이 종료된다면 정말 당황스럽겠죠? 숫자를 입력할 곳에 문자를 넣는 것처럼, 우리가 통제할 수 없는 돌발 상황은 언제나 일어날 수 있습니다. 예외가 발생했을 때 미리 정해둔 방법으로 대처하는 기술이 예외 처리입니다.

코드를 작성하다 보면 예상치 못한 버그가 발생하는 건 정말 흔한 일이죠. 이럴 때 필요한 것이 바로 디버깅(Debugging)입니다. 디버깅(Debugging)은 프로그램이 실행되는 동안 내부 상태를 자세히 들여다보고, 버그의 원인을 찾아내 수정하는 과정을 말해요.

"이 코드 한 줄만 테스트해보고 싶은데..." 이런 생각을 할 때마다 프로젝트를 만들고, 코드를 작성하고, F5를 눌러 컴파일하고 실행하는 과정을 반복하고 있지는 않으신가요? 비주얼 스튜디오 안에 숨겨진 작은 실험실 기능이 있습니다.

여러분은 컴퓨터에 마우스, 키보드 등 다양한 장치를 연결할 때 어떤 포트를 사용하시나요? 대부분 USB 포트를 떠올리실 겁니다. 기능이 전혀 달라도, USB 규격만 맞으면 컴퓨터에서 사용할 수 있죠. C#에서도 USB 포트와 같은 역할을 하는 멋진 기능이 있습니다.

"일부는 내가 미리 만들어주고, 핵심 기능만 각자 만들게 할 순 없을까?" 이럴 때 사용하는 것이 바로 추상 클래스(Abstract Class)입니다. 마치 일부는 완성되어 있고, 일부는 비어있는 '미완성 설계도'와 같습니다.

C#에서 클래스 내의 데이터를 외부에서 접근해야 할 때가 많습니다. 가장 쉬운 방법은 변수를 public으로 열어두는 것이지만, 이건 마치 우리 집 대문을 활짝 열어두는 것과 같습니다. C#은 이런 문제를 해결하기 위해 속성(Property)이라는 기능을 제공합니다.

C#에서 class를 만들때, 생성자와 속성들을 일일이 타이핑하곤 하죠. 그런데 "데이터 묶음이 필요할 뿐인데, 코드가 많지?"라고 생각해 본 적이 있나요? C# 9.0부터 이런 고민을 한 방에 해결해 줄 레코드(Record)라는 기능이 도입되었습니다.

"이 메서드 안에서만 잠깐 쓸 건데... 굳이 새 클래스 파일을 만들어야 하나?" C#은 이럴 때 실용적이고 편리한 무명 형식(Anonymous Type)을 제공하고 있습니다. 무명 형식은 마치 정보를 급하게 메모해야 할 때, 포스트잇에 쓰는 것과 같아요.

C#에서 다루려는 데이터가 색상 값(R, G, B)처럼 단순하다면 어떨까요? 우리는 항상 class라는 거대한 도구를 사용하는 것이 최선일까요? 이럴 때를 위해 C#은 구조체(struct)라는 가볍고 빠른 '값 형식(Value Type)'의 컨테이너를 제공합니다.

C#에서 여러 개의 결과를 한 번에 돌려주고 싶을 때 여러분은 어떻게 해결하셨나요? 굳이 새로운 class나 struct를 정의하기는 귀찮고 번거롭습니다. 이럴 때 '간단한 종이봉투' 역할을 해주는 튜플(Tuple)이라는 기능이 있습니다.

"하는 일은 똑같은데, 형식만 다르다고 메서드를 따로 만들어야 하나요?" 똑같은 로직을 형식만 바꿔서 반복적으로 작성하는 건 비효율적입니다. 이럴 때 C#에서는 '만능 상자'를 만드는 도구, 제네릭(Generic)을 제공합니다.

C#에서 제네릭은 어떤 타입이든 담을 수 있는 '만능 상자'입니다. 그런데 때로는 너무 만능이라 문제가 되기도 합니다. 무엇이 들어있는지 알 수 없기 때문에, 특정 기능을 사용할 수가 없는 것이죠. 바로 이럴 때, where라는 자물쇠를 거는 기능이 필요합니다.

C#에서 여러 개의 데이터를 한꺼번에 관리해야 할 때가 정말 많습니다. 이럴 때 사용하는 것이 바로 컬렉션(Collection)입니다. 이번 글에서는 C#의 역사를 함께한 ArrayList와 오늘날 표준으로 사용되는 List<T>에 대해 알아보겠습니다.

지난 글에서 우리는 순서가 있는 데이터 묶음의 표준, List<T>에 대해 알아봤습니다. 정말 대부분의 상황에서 유용하게 쓰이죠. 때로는 데이터에 '규칙'을 부여하고 싶을 때가 있습니다. 이번 글에서는 데이터의 저장 순서나 접근 방식이 특별한 컬렉션을 살펴보겠습니다.

"내가 직접 만든 클래스도 이렇게 배열이나 딕셔너리처럼 데이터를 다룰 수 있으면 얼마나 좋을까?" 놀랍게도, C#은 바로 그 기능도 제공합니다! 인덱서(Indexer)를 사용하면 우리가 만든 객체를 마치 배열처럼 인덱스로 접근할 수 있게 만들 수 있습니다.

for문으로는 순회할 수 있겠지만, C#의 우아한 반복문인 foreach를 사용할 수 없다니! 마치 열쇠가 없어 들어가지 못하는 보물창고를 보는 기분입니다. 이럴 때 우리는 IEnumerable<T>라는 마법의 열쇠, 즉 인터페이스에 있습니다.

만약, C#에서 '메서드(기능)' 자체를 변수에 담아서 전달할 수 있다면 어떨까요? 마치 '심부름꾼'에게 오늘은 "A 가게에 가서 우유 사 와!"라고 시키는 것처럼, 수행할 임무(메서드) 자체를 동적으로 바꿔서 전달하는 개념이 대리자(Delegate)입니다.

한 가지 아쉬운 점이 있었습니다. "정수를 계산하는 Calculate 대리자를 만들었는데, 이번엔 실수를 계산해야 하네? 하는 일은 똑같은데..." 우리의 심부름꾼이 '정수 심부름'만 할 수 있는 전문가였던 탓입니다. 이때 '만능 심부름꾼'이 있다면 얼마나 좋을까요?

C#에서 대리자는 메서드를 변수처럼 다루는 강력한 기능입니다. 만약 한 명의 심부름꾼에게 여러 개의 임무를 순서대로 시키고 싶다면 어떻게 해야 할까요? 이럴 때 C#은 여러 개의 메서드를 체인처럼 연결하여 순차적으로 호출하는 강력한 기능을 가지고 있습니다.

C# 2.0부터 익명 메서드(Anonymous Method)가 도입되었습니다. 이름 그대로, 이름 없이 바로 그 자리에서 만들어 대리자에 할당하는 메서드입니다.

객체 지향 프로그래밍을 하다 보면, 한 객체에서 어떤 일이 발생했을 때, 그 사실을 다른 여러 객체에 알려줘야 하는 상황이 정말 많습니다. 이런 문제를 해결하기 위해 C#은 이벤트(Event)라는 발행-구독(Publish-Subscribe) 패턴을 제공합니다.

C# 3.0에서 람다식(Lambda Expression)이 등장했습니다. 람다식은 간단히 말해, 메서드를 하나의 '식(Expression)'으로 표현하는 방법입니다.

우리가 작성하는 코드는 본질적으로 컴퓨터에 내리는 '지시사항'들의 묶음입니다. 그런데 만약, 이 '지시사항' 자체를 하나의 데이터처럼 다룰 수 있다면 어떨까요? 바로 이 마법 같은 일을 가능하게 해주는 기술이 C#의 식 트리(Expression Tree)입니다.

C# 개발자들은 생각했습니다. "람다식에서만 '=>'를 쓰기엔 너무 아까운데?" 그래서 C# 6.0부터 식으로 이루어지는 멤버(Expression-bodied Members)라는 멋진 기능이 도입되었습니다.

C#에서 보이지 않는 곳에서 묵묵히 일하는 친구가 있습니다. 바로 가비지 컬렉터(Garbage Collector)입니다. 프로그램이 사용한 메모리도 누군가는 깔끔하게 정리해 주어야 하죠. C#에서는 가비지 컬렉터가 메모리 청소를 자동으로 담당해 준답니다.

C#에서 가비지 컬렉터가 매번 전체 메모리를 샅샅이 뒤진다면, 그로 인한 성능 저하(Stop-the-World)를 무시할 수 없을 거예요. 그래서 .NET의 똑똑한 가비지 컬렉터는 훨씬 더 효율적인 전략을 사용합니다. 바로 세대별 가비지 컬렉션입니다.

가비지 컬렉터는 세대별 가비지 컬렉션을 사용해서 메모리를 효율적으로 청소합니다. 만약에 객체의 크기가 거대하다면 가비지 컬렉터는 어떻게 처리할까요? 이럴 때 .NET은 LOH(Large Object Heap)라고 하는 환경을 제공합니다.

C#에서는 조건에 맞는 데이터만 골라내거나, 원하는 순서대로 정렬하고, 또 그중에서 필요한 정보만 쏙쏙 뽑아내야 할 때가 있습니다. 이런 데이터 처리의 번거로움을 마법처럼 해결해 주는 C#의 강력한 기능, LINQ에 대해 알아보려고 합니다.

Dictionary를 만들고, foreach를 돌면서 키가 있는지 확인하고, 없으면 새로 만들고, 있으면 기존 리스트에 추가하고... 생각만 해도 코드가 복잡해질 것 같지 않나요? 이런 데이터 분류 작업을 해결해 주는 LINQ의 group by에 대해 알아보겠습니다!

실제 프로젝트를 하다 보면 데이터가 한곳에만 깔끔하게 모여있는 경우는 드뭅니다. 이럴 때 '특정 길드에 속한 모든 플레이어의 이름'을 찾으려면 어떻게 해야 할까요? 흩어져 있는 데이터를 연결해서 의미 있는 정보로 만들어주는 join에 대해 알아보겠습니다!

LINQ를 사용하다 보면 select는 정말 밥 먹듯이 사용하게 되는 단골손님이죠. "이 리스트에서 이름만 뽑아줘!"와 같은 원하는 데이터만 쏙쏙 골라내는 역할을 하니까요. 그런데 select가 우리에게 돌려주는 결과물에 대해 깊이 생각해 보신 적 있나요?

"만약 프로그램이 실행되는 도중에 자신의 구조를 뜯어보고, 심지어 그걸로 무언가를 할 수 있다면 어떨까요?" 사실 C#에는 이런 마법 같은 기능을 하는 리플렉션이 존재합니다. 이번 글에서는 리플렉션이 무엇인지 그 '개념'에 대해 알아보겠습니다!

C#의 리플렉션(Reflection)에 대한 개념은 이해했는데, 막상 "어떤 코드를 써야 하는 거지?"라는 궁금증이 드셨나요? 오늘은 그 궁금증을 해결해 줄 개발자의 가장 든든한 친구, Microsoft Learn에 대해 알아보고, 리플렉션의 핵심을 소개해 드릴게요!

지금까지 우리는 리플렉션의 핵심인 Type클래스를 탐험하며 설계도를 손에 넣었으니, 이제 직접 무언가를 만들어 볼 차례겠죠? 이번 포스팅에서는 런타임에 클래스 이름만으로 동적으로 객체를 생성하고, 그 객체의 메소드까지 호출하는 방법에 대해 깊이 파고들어 보겠습니다!

만약 프로그램이 실행되는 도중에 새로운 클래스의 설계도를 그려내고, 그 설계도로 객체까지 스스로 만들어낼 수 있다면 어떨까요? 이번 포스팅에서는 리플렉션에서 가장 강력한 기능, Reflection.Emit을 이용한 '동적 형식 내보내기'에 대해 알아보겠습니다.

문서에 '긴급'을 붙이는 것처럼 애트리뷰트(Attribute)는 우리 코드에 특별한 꼬리표를 달아주는 역할을 합니다. 이번 포스팅에서는 코드에 '의미'와 '정보'를 부여하는 애트리뷰트에 대해 알아보려 합니다.

로그를 남길 때마다 현재 메소드 이름을 직접 문자열로 쓰는 거, 귀찮지 않으셨나요? 혹은 버그를 추적할 때 "이 메소드는 어디서 호출된 거야?"라며 막막했던 경험은요? C#에는 이런 반복 작업을 마법처럼 해결해 주는 호출자 정보 애트리뷰트가 있습니다.

C# 애트리뷰트와 리플렉션의 세계를 탐험하는 마지막 여정입니다. 이번에는 우리가 직접 우리만의 규칙을 담은 애트리뷰트를 만들고, 리플렉션을 이용해 이 규칙을 검사하는 유효성 검사(Validation) 프레임워크를 흉내 내보겠습니다.

C#은 대표적인 정적 타입 언어(Statically Typed Language)입니다. 그런데 가끔은 이런 엄격함이 답답하게 느껴질 때가 있습니다. 외부 라이브러리나 다른 언어와 소통해야 할 때처럼요. 이럴 때 우리에게 자유를 선물하는 dynamic 형식이 있습니다.

C#에서 엑셀을 다루는 방법은 여러 가지가 있는데요, 처음 접하면 어떤 방법을 써야 할지 막막하게 느껴질 수 있습니다. 이번 포스팅에서는 C#에서 엑셀을 제어하는 대표적인 3가지 방법을 알아보고, 각각의 장단점과 어떤 방법을 선택해야 할지 정리해 드릴게요!

만약 C#의 정적 타입 세상 안에서 파이썬(Python)이나 루비(Ruby)처럼 유연한 동적 타입 언어의 코드를 실행할 수 있다면 어떨까요? C#에는 이를 가능하게 하는 비밀 병기, DLR(Dynamic Language Runtime)이 있습니다.

특정 폴더에 어떤 파일이 있는지, 크기는 얼마인지에 대한 정보가 궁금할 때가 많죠? 이번 글에서는 파일과 폴더(디렉터리)의 정보를 조회하는 방법에 대해 알아보려고 합니다. 먼저 정보를 조회할 줄 알아야 나중에 생성, 수정, 삭제도 할 수 있습니다.

지난번에는 C#에서 파일과 폴더 정보를 조회하는 방법을 알아봤습니다. 이제는 여러분이 직접 C#으로 폴더와 파일을 생성하는 방법을 배워볼 차례입니다. 이번 글에서는 System.IO 네임스페이스의 또 다른 주인공들을 다뤄보겠습니다.

지난번에 우리는 파일과 폴더의 정보를 조회하고, 새로 만드는 방법까지 알아봤습니다. 만약 여러분이 파일과 폴더를 관리한다면 '복사'와 '삭제'하는 기능을 모르면 안 되겠죠? 이번 글에서는 파일과 폴더(디렉터리)를 복사/삭제하는 방법에 대해 알아보겠습니다.

'마법의 손수레'처럼, 디렉터리 복사를 아주 간단하게 처리해 주는 기능이 .NET 프레임워크 안에 숨어있답니다. 이번 글에서는 Microsoft.VisualBasic 라이브러리를 활용하여 디렉터리를 단 한 줄의 코드로 복사하는 방법을 알아보겠습니다.

파일과 폴더의 세계에서 더 나은 구조를 위해 파일과 폴더를 이동시키거나, 혹은 단순히 파일과 폴더의 이름을 바꾸는 일은 흔하답니다. 이번 글에서는 파일과 폴더를 깔끔하게 정리정돈하는 방법을 알아보겠습니다.

C#에서는 파일에 데이터를 쓰거나 읽기 위해 스트림(Stream)이라는 개념을 사용합니다. 처음 들으면 조금은 막연하게 느껴질 수 있지만, 사실 스트림은 파일뿐만 아니라 네트워크, 메모리 등 다양한 데이터 입출력을 다루는 근본적이고 중요한 개념입니다.

지난번에 데이터가 흐르는 통로, 스트림(Stream)이라는 개념을 알아보았다면 이제 그 통로를 실제 '파일(File)'이라는 목적지에 연결해 볼 시간입니다. 이번 글에서는 C# 파일 입출력의 기본이자 핵심인 FileStream클래스를 다뤄보겠습니다.

지난번에 FileStream의 작동 원리를 바이트 배열을 통해 직접 체험해 봤습니다. 여기서 "Hello World"와 같은 간단한 문자열을 쓰는 과정이 번거롭게 느껴지지 않으셨나요? 그 번거로움을 덜어줄 StreamWriter와 StreamReader를 소개합니다!

지난번에는 StreamWriter와 StreamReader를 이용해 텍스트를 파일에 쓰고 읽는 법을 배웠습니다. 로그나 간단한 메모를 저장하는 용도면 충분하지만 객체을 매번 한 줄 한 줄 저장하는 건 번거롭습니다. 이 문제를 해결해 주는 기술이 객체 직렬화입니다.

JSON 형식은 설정 파일이나 데이터 교환용으로는 정말 훌륭한 방식이죠. 하지만 모든 데이터가 텍스트일까요? 이미지, 사운드, 혹은 게임 세이브 파일처럼 데이터의 크기를 줄이고 처리 속도를 높이는 게 더 중요할 때는 바이너리 데이터로 직접 대화해야 합니다.

우리가 작성한 코드는 결국 컴퓨터 위에서 돌아가게 되는데요, 이때 운영체제는 우리의 프로그램을 어떻게 실행하고 관리할까요? 이번 글에서는 비동기 처리의 바탕이 되는 두 가지 핵심 개념, 프로세스(Process)와 스레드(Thread)에 대해 이야기해 보려 합니다.

우리 만든 C# 프로그램에서 사소한 일을 처리할 때마다 매번 새로운 일꾼(스레드)을 고용(new Thread())하는 것은 너무 비효율적이지 않을까요? 바로 이 문제를 해결하기 위해 등장한 개념이 스레드 풀(Thread Pool)입니다!

스레드 풀은 필요할 때마다 일꾼(스레드)을 빌려 쓰는 효율적인 '인력사무소'입니다. 하지만 오래 걸리는 작업을 스레드 풀에 맡기면 오히려 독이 될 수 있죠. 이번 글에서는 그 '작업의 성격', CPU 바운드 와 I/O 바운드에 대해 이야기해 보려 합니다.

여러 개의 스레드를 사용하다 보면 하나의 데이터에 스레드가 동시에 접근하려는 상황이 발생할 수 있습니다. 이번 글에서는 여러 스레드가 공유된 자원을 사용할 때 발생하는 문제를 예방하고, 질서를 부여하는 기술인 '스레드 동기화'에 대해 알아보겠습니다.

만약 UI 스레드가 파일을 다운로드하는 동안 '블로킹'된다면 어떻게 될까요? 사용자는 그동안 '응답 없음' 화면만 쳐다봐야 할 겁니다. 최악의 사용자 경험이죠! 이번 글에서는 비효율적인 '기다림'을 효율적으로 바꿔주는 async와 await에 대해 알아보겠습니다.

await Task.Delay(3000); 여기서 await가 기다리는 '진동벨'의 정체는 정확히 무엇일까요? Task.Delay(3000)에서 Task는 대체 무슨 역할을 하는 걸까요? 이번 글에서는 Task에 대해 깊이 파헤쳐 보겠습니다.

우리가 Task에 맡기는 일이 항상 "이것 좀 해주세요!"로 끝나는 것은 아닙니다. "데이터베이스에서 사용자 이름을 가져와 주세요!"처럼, 작업의 '결과물'이 필요한 경우가 많죠. 이번 글에서는 Task<TResult>에 대해 알아보겠습니다.

100만 개의 이미지 파일 각각에 워터마크를 박는 작업을 상상해 보세요. 이럴 때 여러 개의 CPU 코어를 모두 활용하고 싶을 때는 어떻게 해야 할까요? CPU의 모든 코어가 함께 일하게 만드는 마법, Parallel 클래스에 대해 알아보겠습니다.

만약 1GB짜리 거대한 로그 파일을 읽는 동안 프로그램이 멈춰버린다면 어떻게 될까요? 상상만 해도 끔찍하죠? 이번 글에서는 이 문제를 해결하는 가장 올바른 방법, ReadAsync와 WriteAsync에 대해 알아보겠습니다.

컴퓨터에서 흔히 볼 수 있는 계산기, 메모장 같은 프로그램을 한 번쯤 "나도 만들어보고 싶다..."라고 생각해 본 적 없으신가요? 이번 글에서는 나만의 윈도우 데스크톱 애플리케이션을 만들 수 있게 도와주는, Windows Forms(윈폼)에 대해 알아보려고 합니다.