책소개
버전별 주요 기능을 이해한다
제네릭, null 가능 값 타입, 익명 메서드, 이터레이터, LINQ, 람다 표현식, 익명 타입, 객체 초기화자, 쿼리 표현식, 동적 타이핑, async/await, 비동기 메서드, 표현식 본문 멤버, 자동 구현 속성, 문자열 관련 기능, 튜플, switch 표현식, 패턴 매칭 등 다양한 기능을 현실적인 예제와 함께 배운다.
예제 200개로 생산성을 높이는 C# 작성법을 배운다
단순히 C# 공식문서에 있을 법한 사용법만 나열하는 것이 아니라, 200개가 넘는 예제 코드로 문제를 해결하는 다양한 해법을 구체적으로 제시한다. 그리고 이 과정을 지속적으로 거치면서 C# 코드를 간소화하고 생산성을 높이는 방법을 체득할 수 있다.
C# 내부 동작 방식을 이해하여 C# 전문가로 발돋움하자!
이 책은 C#의 내부 동작 방식을 존 스킷만의 경험과 매력적인 통찰로 담아냈다. 이를 통해 C#의 면면을 들여다보고 숨겨진 트릭을 발견하여 C#을 좀 더 C#답게 설계하고 프로그래밍 기술을 극대화하도록 돕는다.
저자소개
구글의 소프트웨어 엔지니어로 런던 사무소에서 근무하고 있다. 담당 업무는 구글 클라우드 플랫폼용 .NET 클라이언트 라이브러리를 개발하는 것인데, 이는 구글과 C#에 대한 열정을 동시에 쏟아부을 수 있는 일이다. C# 표준화를 담당하는 ECMA 기술 그룹의 소장이며 .NET 파운데이션에서 구글을 대표하고 있다. 개발자를 위한 질의응답 사이트인 스택 오버플로(Stack Overflow)에 자주 참여하여 이를 통해 잘 알려져 있다. 그 외에도 콘퍼런스와 사용자 그룹, 블로그에서 연설하고 글을 쓰는 것을 즐긴다. 이 모든 것의 공통점은 다른 개발자와 함께하는 방법이라는 것이며, 이를 통해 많은 것을 배운다.
목차
1부 C#에 대해서
1장 C# 개발자로 살아남기
1.1 진화하는 언어
__1.1.1 어떤 규모의 응용프로그램에도 유용한 타입 시스템
__1.1.2 더욱 간결한 코드 작성
__1.1.3 LINQ를 이용한 단순한 데이터 사용
__1.1.4 비동기
__1.1.5 효율과 복잡성 사이의 균형
__1.1.6 쾌속 진화: 부 버전 도입
1.2 진화하는 플랫폼
1.3 진화하는 커뮤니티
1.4 진화하는 책
__1.4.1 이 책이 다루는 범위
__1.4.2 Noda Time을 이용하는 예제
__1.4.3 용어 선택
1.5 요약
2부 C# 2-5
2장 C# 2
2.1 제네릭
__2.1.1 예제를 통한 소개: 제네릭 이전의 컬렉션
__2.1.2 시간을 절약하는 제네릭
__2.1.3 제네릭이 될 수 있는 것
__2.1.4 메서드의 타입 인수에 대한 타입 추론
__2.1.5 타입 제약 조건
__2.1.6 default와 typeof 연산자
__2.1.7 제네릭 타입의 초기화와 상태
2.2 null 가능 값 타입
__2.2.1 목적: 정보가 없음을 나타내는 방법
__2.2.2 CLR과 프레임워크의 지원: Nullable 구조체
__2.2.3 언어 지원
2.3 델리게이트 작성 단순화
__2.3.1 메서드 그룹 변환
__2.3.2 익명 메서드
__2.3.3 델리게이트의 호환성
2.4 이터레이터
__2.4.1 이터레이터 소개
__2.4.2 지연 수행
__2.4.3 yield 문의 평가
__2.4.4 지연 수행의 중요성
__2.4.5 finally 블록의 평가
__2.4.6 finally 처리의 중요성
__2.4.7 구현 방식에 대한 밑그림
2.5 부가 기능
__2.5.1 partial 타입
__2.5.2 정적 클래스
__2.5.3 속성 접근자에 대해 별도의 접근 한정자 지정
__2.5.4 네임스페이스 별칭
__2.5.5 pragma 지시자
__2.5.6 고정 길이 버퍼
__2.5.7 InternalsVisibleTo
2.6 요약
3장 C# 3: LINQ 그리고 함께 제공되는 모든 것
3.1 자동 구현 속성
3.2 암시적 타이핑
__3.2.1 타이핑 관련 용어
__3.2.2 지역 변수에 대한 암시적 타이핑(var)
__3.2.3 배열에 대한 암시적 타입 지정
3.3 객체 초기화 구문과 컬렉션 초기화 구문
__3.3.1 객체 초기화 구문과 컬렉션 초기화 구문 소개
__3.3.2 객체 초기화 구문
__3.3.3 컬렉션 초기화 구문
__3.3.4 단일 표현식으로 초기화를 수행하는 방식의 이점
3.4 익명 타입
__3.4.1 문법과 기본적인 동작 방식
__3.4.2 컴파일러가 생성한 타입
__3.4.3 한계
3.5 람다 표현식
__3.5.1 람다 표현식 문법
__3.5.2 변수 캡처
__3.5.3 표현식 트리
3.6 확장 메서드
__3.6.1 확장 메서드의 선언
__3.6.2 확장 메서드의 수행
__3.6.3 연쇄적 메서드 호출
3.7 쿼리 표현식
__3.7.1 쿼리 표현식은 C#에서 C#으로의 변환
__3.7.2 범위 변수와 투명 구분자
__3.7.3 LINQ에 어떤 구문을 사용할지 언제 판단할 것인가?
3.8 최종 결과물: LINQ
3.9 요약
4장 C# 4: 상호 운용성의 개선
4.1 동적 타이핑
__4.1.1 동적 타이핑 소개
__4.1.2 리플렉션을 넘어선 동적 타이핑의 동작 방식
__4.1.3 내부 동작에 대한 개요
__4.1.4 동적 타이핑의 한계와 놀라운 점
__4.1.5 동적 타입 사용 가이드
4.2 선택적 매개변수와 명명된 인수
__4.2.1 기본값을 가진 매개변수와 이름을 가진 인수
__4.2.2 메서드 호출의 의미 규정
__4.2.3 버전 관리에 미치는 영향
4.3 COM 상호 운용성의 개선
__4.3.1 Primary Interop Assembly 링크
__4.3.2 COM에서 선택적 매개변수 활용
__4.3.3 명명된 인덱서
4.4 제네릭 변성
__4.4.1 변성에 대한 간단한 사용 예
__4.4.2 인터페이스와 델리게이트 선언 시 변성을 지정하는 문법
__4.4.3 변성의 제약 사항
__4.4.4 제네릭 변성에 대한 실용적 사례
4.5 요약
5장 비동기 코드 작성
5.1 비동기 함수 소개
__5.1.1 비동기와의 첫 만남
__5.1.2 첫 번째 예제 쪼개기
5.2 비동기에 대해
__5.2.1 비동기 수행의 기본
__5.2.2 동기화 컨텍스트
__5.2.3 비동기 메서드 모델링
5.3 비동기 메서드 선언
__5.3.1 비동기 메서드의 반환 타입
__5.3.2 비동기 메서드의 매개변수
5.4 await 표현식
__5.4.1 대기 가능 패턴
__5.4.2 대기 표현식의 제약 사항
5.5 반환값을 둘러싸고 있는 부분
5.6 비동기 메서드의 흐름
__5.6.1 무엇을 언제까지 대기하는가?
__5.6.2 대기 표현식의 평가
__5.6.3 대기 가능 패턴 멤버의 이용
__5.6.4 예외 뜯어보기
__5.6.5 메서드 완료
5.7 비동기 익명 함수
5.8 C# 7에 도입된 사용자 정의 태스크 타입
__5.8.1 99.9%의 사용 예: ValueTask
__5.8.2 나머지 0.1%의 사용 예: 사용자 정의 태스크 타입 작성
5.9 C# 7.1에서 지원하는 비동기 Main 메서드
5.10 활용 팁
__5.10.1 ConfigureAwait로 컨텍스트를 저장하는 것을 피하라
__5.10.2 여러 작업이 독립적으로 수행될 수 있도록 작성하고 이를 병렬적으로 수행하라
__5.10.3 동기 코드와 비동기 코드를 섞어 쓰지 마라
__5.10.4 취소가 가능하도록 코드를 작성하라
__5.10.5 비동기성을 테스트하라
5.11 요약
6장 비동기 구현
6.1 컴파일러가 생성한 코드의 구조
__6.1.1 스텁 메서드: 사전 준비와 첫걸음 떼기
__6.1.2 상태 머신의 구조
__6.1.3 MoveNext( ) 메서드(고수준)
__6.1.4 SetStateMachine 메서드와 상태 머신 박싱의 조화
6.2 MoveNext( )의 간단한 구현
__6.2.1 구체적인 예
__6.2.2 MoveNext( ) 메서드의 일반적인 구조
__6.2.3 대기 표현식에 대한 고찰
6.3 제어 흐름이 MoveNext( )에 미치는 영향
__6.3.1 대기 표현식 사이의 제어 흐름은 단순하다
__6.3.2 루프 내에 대기 표현식이 있는 경우
__6.3.3 try/finally 블록 내에 대기 표현식이 있는 경우
6.4 실행 컨텍스트와 흐름
6.5 사용자 정의 태스크 타입 재검토
6.6 요약
7장 C# 5의 보너스 기능
7.1 foreach 루프 내에서 변수 캡처
7.2 호출자 정보 특성
__7.2.1 기본적인 동작
__7.2.2 로깅
__7.2.3 INotifyPropertyChanged 구현 단순화
__7.2.4 호출자 정보 특성의 지엽적 특이성
__7.2.5 예전 버전의 .NET에서 호출자 정보 특성을 사용하는 방법
7.3 요약
3부 C# 6
8장 매우 세련된 속성과 표현식 본문 멤버
8.1 속성의 간단한 역사
8.2 업그레이드된 자동 구현 속성 기능
__8.2.1 읽기 전용 자동 구현 속성
__8.2.2 자동 구현 속성 초기화
__8.2.3 구조체 내의 자동 구현 속성
8.3 표현식 본문 멤버
__8.3.1 계산이 필요한 읽기 전용 속성을 더 간단히 구현하는 방법
__8.3.2 표현식 본문 메서드, 표현식 본문 인덱서, 표현식 본문 연산자
__8.3.3 C# 6의 표현식 본문 멤버가 가지는 제약 사항
__8.3.4 표현식 본문 멤버 사용 지침
8.4 요약
9장 문자열 관련 기능
9.1 NET에서 문자열 포매팅을 수행하는 방법 요약
__9.1.1 단순 문자열 포매팅
__9.1.2 포맷 문자열을 이용하여 사용자 정의 포매팅 수행하기
__9.1.3 현지화
9.2 보간 문자열 리터럴 소개
__9.2.1 간단한 보간
__9.2.2 보간 문자열 리터럴 내에서의 포맷 문자열
__9.2.3 보간 축자 문자열 리터럴
__9.2.4 컴파일러가 보간 문자열 리터럴을 다루는 방법(첫 번째)
9.3 FormattableString을 사용한 현지화
__9.3.1 컴파일러가 보간 문자열 리터럴을 다루는 방법(두 번째)
__9.3.2 컬처를 지정하여 FormattableString 포매팅하기
__9.3.3 FormattableString의 다른 사용 예
__9.3.4 이전 버전의 .NET에서 FormattableString을 사용하려면
9.4 활용법, 사용 지침, 한계
__9.4.1 개발자와 컴퓨터, 하지만 최종 사용자는 아닌…
__9.4.2 보간 문자열 리터럴의 엄격한 제약
__9.4.3 할 수 있지만 해서는 안 될 때
9.5 nameof로 식별자에 접근
__9.5.1 nameof의 첫 번째 사용 예
__9.5.2 nameof의 일반적인 사용 예
__9.5.3 nameof를 사용할 때 주의해야 할 트릭과 함정
9.6 요약
10장 간결한 코드 작성을 위한 다양한 기능
10.1 using static 지시자
__10.1.1 정적 멤버 임포트
__10.1.2 확장 메서드와 using static
10.2 객체 초기화자와 컬렉션 초기화자의 개선
__10.2.1 객체 초기화자 내에서의 인덱서
__10.2.2 컬렉션 초기화자 내에서 확장 메서드 사용
__10.2.3 테스트 코드와 제품 코드
10.3 null 조건 연산자
__10.3.1 간단하고 안전한 속성 역참조
__10.3.2 null 조건 연산자에 대한 세부 사항
__10.3.3 불 비교 처리
__10.3.4 인덱서와 null 조건 연산자
__10.3.5 null 조건 연산자를 이용하여 작업을 효율적으로 수행하는 방법
__10.3.6 null 조건 연산자의 한계
10.4 예외 필터
__10.4.1 예외 필터의 문법과 의미
__10.4.2 작업 재시도
__10.4.3 부수적으로 로깅 수행
__10.4.4 개별적이고 구체적인 예외 필터 구성
__10.4.5 단순히 throw만 쓰는 것은 어떤가?
10.5 요약
4부 C# 7 그리고 그 이후
11장 튜플을 이용한 구성
11.1 튜플 소개
11.2 튜플 리터럴과 튜플 타입
__11.2.1 문법
__11.2.2 튜플 리터럴에서 추론된 요소 이름(C# 7.1)
__11.2.3 여러 변수를 담을 수 있는 가방처럼 튜플 활용
11.3 튜플 타입과 변환
__11.3.1 튜플 리터럴의 타입
__11.3.2 튜플 리터럴을 튜플 타입으로 변환
__11.3.3 튜플 타입 간 변환
__11.3.4 튜플 변환의 사용
__11.3.5 상속 시 튜플의 요소 이름 확인
__11.3.6 같음 연산자와 같지 않음 연산자(C# 7.3)
11.4 CLR 수준에서의 튜플
__11.4.1 System.ValueTuple<…> 소개
__11.4.2 튜플 요소 이름 처리
__11.4.3 튜플 변환 구현
__11.4.4 튜플의 문자열 표현
__11.4.5 일반적인 동일성 비교와 순차성 비교
__11.4.6 구조적 동일성과 순차성 비교
__11.4.7 웜플 튜플과 거대한 튜플
__11.4.8 제네릭이 아닌 ValueTuple 구조체
__11.4.9 확장 메서드
11.5 튜플의 대체제
__11.5.1 System.Tuple<…>
__11.5.2 익명 타입
__11.5.3 명명된 타입
11.6 용도 및 권고 사항
__11.6.1 비공개 API와 쉽게 변경되는 코드에서 사용
__11.6.2 지역 변수
__11.6.3 필드
__11.6.4 튜플과 동적 타이핑은 잘 어울리지 않는다
11.7 요약
12장 분해와 패턴 매칭
12.1 튜플 분해
__12.1.1 새로운 변수로 분해
__12.1.2 분해 시 기존 변수나 속성에 값을 할당
__12.1.3 튜플 리터럴의 분해에 대한 세부 사항
12.2 튜플이 아닌 타입에 대한 분해
__12.2.1 인스턴스 분해 메서드
__12.2.2 확장 분해 메서드와 오버로딩
__12.2.3 컴파일러가 Deconstruct 호출을 처리하는 방법
12.3 패턴 매칭 소개
12.4 C# 7.0에서 사용할 수 있는 패턴
__12.4.1 상수 패턴
__12.4.2 타입 패턴
__12.4.3 var 패턴
12.5 is 연산자와 함께 패턴 사용
12.6 switch 문에서 패턴 사용
__12.6.1 가드 절
__12.6.2 case 레이블에서 생성한 패턴 변수의 사용 범위
__12.6.3 패턴을 사용하는 switch 문의 평가 순서
12.7 활용 시 고려 사항
__12.7.1 분해를 사용해야 하는 경우
__12.7.2 패턴 매칭을 사용해야 하는 경우
12.8 요약
13장 참조 전달을 통한 효율 개선
13.1 요점 재확인: ref에 대해서 무엇을 알고 있는가?
13.2 참조 지역 변수와 참조 반환
__13.2.1 참조 지역 변수
__13.2.2 참조 반환
__13.2.3 조건 ?: 연산자와 참조 변수(C# 7.2)
__13.2.4 읽기 전용 참조(C# 7.2)
13.3 in 매개변수(C# 7.2)
__13.3.1 호환성을 위한 고려 사항
__13.3.2 in 매개변수의 놀라운 변경 가능성: 외부에서의 변경
__13.3.3 in 매개변수의 오버로딩
__13.3.4 in 매개변수의 사용 지침
13.4 구조체를 읽기 전용으로 선언(C# 7.2)
__13.4.1 배경: 읽기 전용 변수를 사용한 암시적 복사
__13.4.2 구조체에 readonly 한정자 사용
__13.4.3 XML 직렬화는 암시적으로 읽고 쓰는 작업
13.5 참조 매개변수나 in 매개변수를 취하는 확장 메서드
__13.5.1 복사를 피하기 위해 확장 메서드에서 참조 매개변수나 in 매개변수를 사용하는 방법
__13.5.2 확장 메서드에서 ref를 사용할 때의 제한 사항
13.6 유사 참조 구조체(C# 7.2)
__13.6.1 유사 참조 구조체의 규칙
__13.6.2 Span와 stackalloc
__13.6.3 IL 수준에서의 유사 참조 구조체
13.7 요약
14장 C# 7을 이용한 간결한 코드 작성
14.1 지역 메서드
__14.1.1 지역 메서드 내에서의 변수 사용
__14.1.2 지역 메서드의 구현
__14.1.3 사용 지침
14.2 out 변수
__14.2.1 out 매개변수 사용 시 변수 선언을 인라인화
__14.2.2 C# 7.3부터 out 변수와 패턴 변수에 대한 제약이 사라진 부분
14.3 숫자 리터럴 개선
__14.3.1 이진 정수 리터럴
__14.3.2 밑줄 구분자
14.4 throw 표현식
14.5 default 리터럴(C# 7.1)
14.6 명명된 인수의 사용 위치 제약 완화(C# 7.2)
14.7 private protected 접근 한정자(C# 7.2)
14.8 C# 7.3의 사소한 개선 사항
__14.8.1 제네릭 타입 제약 조건
__14.8.2 오버로드 해석의 개선
__14.8.3 자동 구현 속성을 지원하기 위한 필드에 대한 특성
14.9 요약
15장 C# 8 그리고 그 이후
15.1 null 가능 참조 타입
__15.1.1 null 가능 참조 타입은 어떤 문제를 해결하는가?
__15.1.2 참조 타입 사용 시 의미 변경
__15.1.3 null 가능 참조 타입
__15.1.4 컴파일 타임과 런타임 시 null 가능 참조 타입
__15.1.5 damnit 연산자, bang 연산자, null 허용 연산자
__15.1.6 null 가능 참조 타입을 사용하도록 수정한 경험
15.2 switch 표현식
15.3 재귀 패턴 매칭
__15.3.1 패턴 내에서 속성 매칭
__15.3.2 분해 패턴
__15.3.3 패턴에서 타입 생략
15.4 Index와 Range
__15.4.1 Index와 Range 타입 그리고 리터럴
__15.4.2 Index와 Range 사용
15.5 더 많은 비동기 기능 제공
__15.5.1 await를 이용한 비동기 리소스 제거
__15.5.2 foreach await를 이용한 비동기 순회
__15.5.3 비동기 이터레이터
15.6 그 외의 기능들
__15.6.1 기본 인터페이스 메서드
15.7 C# 9.0에 대하여
__15.7.1 init 전용 세터
__15.7.2 레코드
__15.7.3 최상위 구문
__15.7.4 개선된 패턴 매칭
__15.7.5 대상-타입 고려 new 표현식
15.8 참가를 독려하며
부록 버전별 언어 기능