본문 바로가기

C# .Net

[EFC#] effective c# - 4. LINQ 활용

# 컬렉션을 반환하기보다 이터레이터를 반환하는 것이 낫다

- 지연평가로 인해 파라미터의 유효성 확인이 늦어질 경우 다른 메소드에 유효성 확인 로직을 넣고, 통과하면 이터레이터를 리턴으로 호출하는 방식을 쓸 수 있다.



# 루프보다 쿼리 구문이 낫다

- 쿼리 구문을 사용하면 프로그램 논리를 명령형 방식에서 선언적인 방식으로 전환할 수 있다.

- 이렇게 하면 한번의 순회 단계 내에서 여러 작업을 결합하여 단번에 수행할 수 있고

- 원래의 의도도 더 명확하게 구현할 수 있다.



# 시퀀스에 사용할 수 있는 조합가능한 API를 사용해라

- yield return 문을 사용하면 시퀀스를 반환하는 메서드를 쉽게 만들 수 있다.

  - 이를 사용하면 매서드 내에서 시퀀스 내의 개별요소를 저장하기 위해 별도의 저장소를 마련할 필요가 없다.

  - 왜냐하면 정확히 값이 필요한 시점에 입력 시퀀스 상에서 다음 요소를 가져오고, 출력결과가 반드시 필요한 시점에 출력 시퀀스로 결과를 보내기 때문이다.



# Action, Function, Predicate와 순회방식을 분리하라

- 시퀀스를 순회하는 것과, 개별요소에 대해 작업을 수행하는 것(조건식 확인)을 분리해야한다. 이렇게 하면 시퀀스에 대해 다양한 작업을 구현할 수 있다.



# 필요한 시점에 필요한 요소를 생성하라

- 시퀀스를 생성하는 메서드의 참조가 여러군데에서 일어나면 일관성 문제가 발생할 수 있다.

- 때문에 이터레이터 메소드(ex .TakeWhile(delegate actionfunc))를 통해 값이 필요한 순간에 요소를 생성할 수 있도록 하면 좋다.



# 함수를 매개변수로 사용하여 결합도를 낮춰라

- 인터페이스를 작성하고 이를 구현하도록 구조를 가져가면 베이스클래스에 의존하는 방식(부모-자식 상속관계)보다 더 느슨한 결합을 만들 수 있다.

- 상속 기법을 엄밀하게 정의하지 않고 델리게이트를 사용한다 하더라도, 델리게이트에 대한 참조가 필요하므로 런타임에 결합관계는 여전히 발생한다

  - 만약 어떤 객체가 델리게이트를 나중에 다시사용하기위해 그 복사본을 저장해두면 이 객체는 델리게이트의 생명주기에 영향을 미치게 된다. 즉, 참조하는 델리게이트가 이전보다 오랜기간 살아있게 된다.



# 확장 메서드는 절대 오버로드하지 마라

- 확장메서드를 사용하는 대부분의 경우가 기존에 개발된 타입을 개선하기 위해서이지 타입의 본질적인 동작방식을 변경하기 위한 것은 아니기 때문이다.

- 개발자가 실수로 오버로드 된 메서드와 그렇지 않은 메서드의 네임스페이스를 잘못 참조하게되면 프로그램 동작방식이 바뀐다.



# 쿼리 표현식과 메서드 호출 구문이 어떻게 대응되는지 이해하라

- 컴파일러는 메서드의 오버로딩이나 타입 바인딩 과정을 처리하기에 앞서, 쿼리 표현식을 메서드 호출 구문으로 변환하는 과정을 우선적으로 수행한다.



# 쿼리를 사용할때는 즉시평가보다 지연 평가가 낫다

- 무한 시퀀스 표현이 가능하고

- 필터된 시퀀스 처리를 우선적으로 하여 리소스 절약을 할 수 있다



# 메서드보다 람다 표현식이 낫다

- 메서드 표현식으로 데이터 필터링등이 일어나면 T-SQL 표현식(표현식트리)으로 변경할수가 없다.

- 람다로 표현하면 전체 쿼리를 단번에 처리할 수 있다.



# function과 action 내에서는 예외가 발생하지 않도록 하라

- 람다는 시퀀스 내의 표함된 요소값을 직접 수정한다. 작업중에 예외가 발생하면 순회중인 데이터의 일부만 변경될수도 있다.



# 지연수행과 즉시 수행을 구분하라

- 반환값이 필요한데이터는 캐싱을 하고, 그렇지 않은 데이터(ex IQueryable타입 데이터)는 람다 구현을 하여 적절한 성능 최적화를 해야한다.



# 값비싼 리소스를 캡처하지 말라

- 클로저와 캡처된 변수는 일반적인 객체 수명주기를 벗어날 확률이 높다.

- 바인딩된 리소스는 캡슐화하고, 데이터는 람다식을 사용해 지연평가하자.



# IEnumerable<T> 데이터 소스와 IQueryable<T> 데이터 소스를 구분하라

- IQueryable<T>는 LINQ to SQL 라이브러리가 모든 쿼리문을 결합하여 단번에 SQL 결과를 생성한다.

- IEnumerable의 정렬작업은 로컬 머신에서 이뤄진다.

- 런타임시 IQueryable객체면 Linq to SQL 사용이 가능하도록, 아니면 Linq to Object를 사용할 수 있도록 객체타입을 변환해주는 AsQueryable()함수 호출을 사용하자



# 쿼리 결과의 의미를 명확히 강제하고, Single()과 First()를 사용하라



# 바인딩된 변수는 수정하지 말라

- 클로드에 외부 변수를 캡쳐할경우 중간에 값 변경시 예상치 못한 결과가 나타날 수 있다.