ITEM 31 :: EFFECTIVE C#
안녕하세요, 31번째 시간입니다. LINQ라고 쉽지는 않네요.
이번 챕터는 시퀀스에 사용할 수 있는 조합 가능한 API를 작성하라, 입니다. API를 작성할 일이 없었고, 비슷한 일도 없었기 때문에 쉽지않은 접근이었습니다만, 쉽게 풀어 말하면, 시퀀스 하나에 여러개의 API를 조합하여 사용할 수 있는 API를 개발하여 유연성을 높이자는 이야기인 듯 합니다. 그럼, 시작할게요.
설명
-
반복 구문이 필요한 경우는 대부분 단일 요소가 아니라 시퀀스(컬렉션)를 처리하는 알고리즘을 작성하는 경우가 많다.
-
이 때, foreach 혹은 for, while을 사용하게 되는데, 이를 사용할 때에는 매개변수로 컬렉션을 받아와서 컬렉션에 포함된 요소들을 살펴보거나, 내용을 수정하거나, 혹은 그 중 일부만 필터링해서 또 다른 컬렉션에 그 결과를 저장한 후 반환하는 식으로 작성한다.
-
이는 효율성에 좋지않다. 그 이유는 전체 컬렉션을 대상으로 하나의 작업만을 하는 것이 아니고 여러 작업 끝에 원하는 결과물을 얻을 수 있는 경우가 대부분이기 때문이며, 이 작업에 대한 중간 결과물을 저장할 컬렉션이 필요할 수도 있다(큰 용량의 컬렉션일 수도 있다.)
-
또한 하나의 컬렉션 전체에 대해 작업을 할 때 이 작업이 끝나기 전까지는 두 번째 작업을 못하게 되는데, 이러한 작업을 하는 경우에는 대부분 각 작업마다 전체 컬렉션을 매번 순회해서 하기 때문에, 다단계로 구성된 알고리즘을 수행하는 경우 전체적으로 수행 시간이 길어질 수 밖에 없다.
-
따라서 메서드를 각각의 작업별로 나누고 메서드를 호출하게 되면 중간 저장소도 필요없게 되고, 속도도 개선되지만, 이렇게 되면 함수의 재사용성이 낮아진다(너무 길고, 단번에 실행하고, 특화되어있어, 이를 호출하게 되는 건 분할된 각각의 개별 메서드보다 훨씬 적어질 수 밖에 없다.)
-
전 챕터에서도 말했듯이 따라서, 시퀀스를 다루는 메서드를 사용할 때는 C# 이터레이터를 사용하는 것이 좋다. 이는 출력도 출력시퀀스에서 하고 싶을 때 할 수 있고, 입력의 경우에도 입력시퀀스에서 올바른 순서의 정보를 가져온다.
-
다만, 반환타입을 Ienumerable
로 정의하는 방식은 일반적인 메서드 선언 방식과는 사뭇 다른점이 있어서 개발자들이 익숙하지 않은 것도 사실이다. -
하지만 장점이 훨씬 많다. 먼저 Ienumerable
로 반환타입을 정의하게되면 다양한 방식으로 조합하여 사용할 수 있는 알고리즘 빌딩 블록이 자연스럽게 만들어지므로, 재사용성이 좋아진다. -
또, 이렇게 작성된 여러 메서드를 하나로 조합하면 전체 시퀀스를 한 번만 순회하면서 조합된 메서드 세트를 수행할 수 있으므로, 런타임의 효율이 개선된다.
-
이터레이터 메서드는 N번째 요소가 요청되었을 때 비로소 N번째 결과를 생성하기 위해 코드를 실행하기 때문이다.
-
이러한 지연수행모델 덕분에, 전통적인 방식으로 알고리즘을 구현한 경우 반드시 필요한 추가 저장소를 사용하지 않을 수 있으며, 각 메서드가 구현하고 있는 알고리즘의 조합 가능성도 높아진다.
-
이터레이터 메서드를 사용하도록 라이브러리를 개선하면 다수의 CPU 코어에 서로 다른 작업을 할당할 수 있으므로 전체적 성능이 더욱 개선된다.
-
또한 이러한 이터레이터 메서드를 구현할 때는 작업의 대상이 되는 개별 요소의 타입에 대한 가정을 덜 할 수 있으므로, 제네릭 메서드로 변경하기에도 용이하며 결국 재사용성이 더욱 좋아진다.
-
이터레이터 메서드는 작게 만들면 만들수록 좋다. 또한 입출력 시퀀스를 하나씩 두는 것을 룰로써 사용하면 더욱 조합이 쉽게 된다. 또한 이터레이터 메서드를 여럿 만들어두면 복잡한 다단계작업을 거쳐야 하는 경우에도 쉽고 간단하게 만들 수 있게 된다.
-
이터레이터는 Yield와 같이 사용하면 좋다. (Yield는 현재 요소의 값을 반환하고, 한칸 앞으로 이동하여 다음에는 다음 값을 반환한다.) yield는 return(현재 요소의 값을 반환)과 break(이터레이터 루프에서 빠져나올 때 사용)에서 사용할 수 있다. 이에대한 정보는 C# Yield에 있으니 확인해보자.
결론
읽어보니, 단순히 API를 작성할 때 뿐만 아니라 컬렉션을 사용할 때 참고하면 좋을 내용이었다. 전전 장에서, 말한, 컬렉션을 반환하기보다 반복자를 반환하라,에 대한 내용의 상세와 같은 부분이 있다. 또, 여기서는 이터레이터 메소드라는 개념이 나오는데, 이는 시퀀스에 접근하는 부분의 코드를 이터레이터 메소드로 대체하게 되면 데이터 접근에 대한 효율성이 좋아지고 재사용성이 좋아진다는 이야기였다.
결론적으로, IEnumerable