쿼리를 정의한다고 해서 결과 데이터나 시퀀스를 즉각적으로 얻어오는 것이 아니다. 실제로는 쿼리를 정의하는 작업은 수행 시에 어떤 과정으로 작업을 수행할지에 대한 절차만을 정의한 것에 지나지 않는다. 지연 평가(lazy evaluation) : 실제로 쿼리의 결과를 이용하여 순회를 수행할 때 결과가 생성. 즉시 평가(eager evaluation) : 일반 변수를 사용하는 것처럼 즉각적으로 그 값을 얻어오는 것. 지연 평가는 어떻게 동작하는가? 아래 코드는 현재 시간을 생성하는 시퀀스를 작성하고 그 시퀀스를 세계 공용 포맷으로 다시 변경하는 코드이다. var sequence1 = Generate(10, () => DateTime.Now); // 오전 8:00 Thread.Sleep(60000); /..
LINQ는 쿼리 언어와 그 쿼리 언어를 일련의 메서드 집합으로 변환하는 2개의 핵심 구조를 기반으로 한다. C# 컴파일러는 쿼리 언어로 작성된 쿼리 표현식을 메서드 호출 구문으로 변환해준다. C#은 쿼리 표현식 패턴에 포함된 개별 메서드가 어떤 의미를 가지고 있는지 전혀 개의치 않는다. 예로들어 컴파일러는 Where()과 같은 메서드가 쿼리 표현식의 패턴에서 의도하는 동작을 온전히 수행하는지를 확인하지 않으며, 구문상의 오류만을 확인할 뿐이다. 따라서 유효한 구조의 메서드라 하더라도 그 메서드가 우리가 의도하는 바를 제대로 구현하고 있는지를 컴파일러가 확인할 수 없다. 따라서 우리는 쿼리 표현식과 메서드 호출 구문이 어떻게 대응되는지 제대로 알아둘 필요가 있다. where : Where() w..
확장 메서드는 설계 의도를 드러내는 방법으로는 썩 훌륭하지 않다. 확장 메서드를 사용하는 대부분의 경우가 기존에 개발된 타입을 개선하기 위해서이지 타입의 본질적인 동작 방식을 변경하기 위해서는 아니기 때문이다. 왜 확장 메서드로 타입을 확장해서는 안 되는가? 확장 메서드를 이용하여 인터페이스에 대한 기본 구현체를 제공하는 것이 괜찮은 방법인 것은 분명하지만 타입을 확장하기 위한 용도로 사용하는 것은 적절하지 않다. 확장 메서드를 과도하게 사용하거나 잘못 사용하면 메서드 충돌로 인해 유지보수 비용이 급격하게 증가하는 곤경에 처할 수 있기 때문이다. 예시) Person 클래스 public sealed class Person { public string FirstName { get; set; } pub..
보통의 경우엔 클래스 내의 메서드를 정의하기 위해서 베이스 클래스나 인터페이스를 정의하고 이렇게 정의된 내용을 기반으로 코딩을 한다. 하지만 이 외에도 '함수를 매개변수로 취하는 방식'을 활용한다면 기존의 컴포넌트나 라이브러리와 함께 사용해야 하는 코드를 개발할 때 상당히 큰 도움이 된다. 왜 함수를 매개변수로 취하는가? 함수를 매개변수로 취하게 되면 우선 개발자가 더 이상 구상 타입(concrete type)을 작성할 필요가 없다. 오히려 추상화된 정의를 통해 종속성을 다루는 것을 의미한다. 그리고 API를 좀 더 단순하게 만들 수 있다. 실제로 델리게이트를 사용하여 컴포넌트의 계약을 기술하면 클라리언트 측에서 코드를 사용하기가 쉬워진다. 또한 의존성을 낮춰 단위 테스트를 수행하기 쉬워지고 다른 환..
이터레이터 메서드가 입력 변수로 반드시 시퀀스를 받을 필요는 없다. 이터레이터 메서드를 구현할 때 새로운 시퀀스를 출력하기 위해 yield return을 자주 사용하는데 이 과정에서 입력 시퀀스를 활용하는 대신 새로운 팩토리 메서드를 이용할 수도 있다. 작업을 수행하기 전에 필요한 요소를 모두 생성해서 컬렉션에 저장해두는 대신 필요할 때마다 개발 요소를 생성하는 식이다. 이 방법으로 코드를 작성하면 사용 되지 않을 요소를 미리 생성하는 것을 피할 수 있다. 예시 1) 정숫값의 시퀀스 생성 static IList CreateSequence(int numberOfElements, int startAt, int stepBy) { var collection = new List(numberOfElements); ..
이터레이터 메서드의 사용 예를 살피다 보면 크게 두 가지 유형이 있다. 시퀀스 내의 개별 항목을 이용하여 작업을 수행하는 유형 외에도, 시퀀스의 순회 방식에 변경을 주는 유형이 있다. (예를 들어 특정 조건에 부합하는 항목만을 가져오거나, 매 N번째 항목만을 건너뛰며 가져오는 경우) 이처럼 순회 방식에 변경을 주는 유형은 어떤 유형의 업무라도 실제로 개별 항목에 대하여 수행해야 하는 작업의 내용과 시퀀스의 순회 방식은 서로 연관이 없으므로 분리하여 처리할 수 있다. 이 두 가지를 한 번에 수행하면 코드 간의 결합도가 높아지고 중복 코드가 발생하게 된다. Action, Predicate, Function 익명 델리게이트를 사용할 때는 function과 action이라는 두 가지 패턴이 있고 func..
C#은 다양한 반복 구문을 제공하기 때문에 일상적인 개발에는 전혀 지장이 없다. 하지만 쿼리 구문을 사용하는 것이 반복문을 사용하는 것보다 좋은 경우가 꽤 있다. 쿼리 구문의 장점! 1) 프로그램의 논리를 명령형 방식에서 선언적인 방식으로 전환할 수 있다. 2) 질의의 내용을 구성할 수 있을 뿐 아니라 개별 항목에 대해 수행하려는 작업의 수행 시기를 연기할 수 있다. 3) 사용자의 의도를 더 명확하게 드러낼 수 있다. 예시 1) 0부터 99까지의 수에 대해 (X, Y) 좌표 객체를 생성 1-1) 루프 private static IEnumerable ProduceIndices() { for (var x = 0; x
메서드를 작성하다 보면 단일의 객체를 반환하기보다 일련의 시퀀스를 반환해야 하는 경우가 더러 있다. 시퀀스를 반환하는 메서드를 작성해야 한다면 컬렉션을 반환하기보다는 이터레이터를 반환하는 것이 더 좋다. 이터레이터를 반환하면 이를 이용하여 다양한 작업을 좀 더 수월하게 수행할 수 있기 때문이다. cf) 시퀀스(sequence) : 데이터에 순서를 붙여 나열한 것 이터레이터 메서드(iterator method) 이터레이터 메서드란 호출자가 요청한 시퀀스를 생성하기 위해 yield return 문을 사용하는 메서드를 말한다. 다음은 알파벳 소문자에 대한 시퀀스를 생성하는 매우 기본적인 이터레이터 메서드의 구현 예를 나타내었다. public static IEnumerator GenerateAlphabe..