목록C# (122)
방프리
Item 39 : function과 action 내에서는 예외가 발생하지 않도록 하라 람다 표현식의 단점 중 하나가 디버깅하기기 굉장히 어려운 점이다. 실제 메서드가 있는게 아니기 때문에 정확히 어디서 오류가 발생했는지 알기 쉽지 않기 때문이다. 하지만 LINQ 특성상 람다 표현식을 자주 사용할 수 밖에 없다. 그러기에 예외 데이터에 대한 처리도 충분히 고려한 코딩을 만들어주어야 한다. 다음의 코드는 아무런 고려를 하지 않은 채 의식의 흐름대로 작성된 코드다. //모든 직원에게 월급을 5% 인상합니다. var allEmployees = FinmdAllEmployees(); allEmployees.ForEach(e => e.MonthlySalary *= 1.05M); 하지만 잘못된 데이터 혹은 예외가 발생..
Item 38 : 메서드보다 람다 표현식이 낫다. 쿼리 표현식 내의 람다 표현식은 LINQ to Object 방식으로 델리게이트로 변환되어 수행된다. 이외에 LINQ to SQL 방식으로 람다 표현식을 활용하여 표현식 트리를 만들고, 향후 이를 파싱하여 다른 구문을 생성한 후 다른 환경에서 수행하는 방식으로도 동작한다. LINQ to Object는 일반적으로 컬렉션 내의 저장된 요소를 쿼리할 때 사용된다. 확장 메서드로 IEnumerable 입력 시퀸스를 취한다. 반면에 LINQ to SQL은 표현식 트리를 활용한다. 적절한 T-SQL 쿼리를 생성한 후, 이를 데이터베이스에 전달하는 방식이다. 저자는 재사용 가능한 라이브러리를 만드는 경우 LINQ 구문 처리를 위의 경우를 고려해서 만들어야 한다고 한다...
Item 37 : 쿼리를 사용할 때는 즉시 평가보다 지연 평가가 낫다. Linq에서 쿼리를 날린다고 해서 데이터가 즉각적으로 들어오는 것이 아니다. 들어온다는 느낌을 주게 할 뿐 실제로 얻는 데이터가 아니라는 뜻이다. 예를 들어 var sequence1 = Generate(10, () => DateTime.Now); var sequence2 = from value in sequence1 select value.ToUniversalTime(); 구문을 돌릴 때 sequence2에서 사용하는 sequence1 값은 실제 위에서 나온 결과값이 아니라 해당 쿼리를 수행하다 필요한 데이터만 가져오는 방식으로 구동하는 것이다. 이럴 경우 원래 있던 값이 아닌 새로운 값을 가져오게 되는데, 이게 성능 저하의 원인이 ..
Item 36 : 쿼리 표현식과 메서드 호출 구문이 어떻게 대응되는지 이해하라 C#에서 Linq는 절대 빠질 수 없는 기능이다. 복잡한 코드를 간단한 조건식으로 정말 가독성 높게 변경할 수 있기 때문이다. 하지만 제대로 사용하려면 내부에서 어떻게 돌아가는지는 이해하고 사용하는 것이 좋다. Linq와 항상 따라다니는 것들이 있는데, 바로 IEnumerable와 IQueryable이다. 일반적인 where, select 등은 모드 IQueryable에 있는 Where(), Select() 함수를 통해서 동작한다. 또한 몇 가지 키워드는 여러 함수의 과정을 거치기도 한다. 예로, orderby 키워드는 OrderBy(), ThenBy() 함수를 거쳐서 동작한다. 그러므로 최적화를 하고 싶다면, Linq의 해당..
Item 35 : 확장 메서드는 절대 오버로드하지 마라 확장 메서드를 사용하는 목적은 기존에 개발된 타입을 개선하기 위함이지, 타입의 본질적인 동작 방식을 변경하기 위한 것은 아니다. 그렇기 때문에 확장 메서드는 보조의 역할이지 절대 남용해서는 안되는 함수다. 또한 확장 메서드를 관리하는 네임스페이스의 잘못된 사용도 고려해야한다. 차라리 각 객체의 클래스에 정적 메서드를 사용하는 편이 디버깅에도 더 안전하고 융용하게 사용될 수 있다. public static class PersonReports { public static string FormatAsText(Person target) => $"{target.LastName, 20}, {target.FirstName, 15}"; public static s..
Item 34 : 함수를 매개변수로 사용하여 결합도를 낮추라 인터페이스를 정의하는 것보다는 델리게이트를 통해서 느슨한 결합을 만드는 것이 여러 방면에서 굉장히 좋다. /// ///인터페이스로 구현하였을 때 /// public interface IPredicate { bool Match(T soughtObject); } public class List { public void RemoveAll(IPredicate match) { //생략 } } public class MyPredicate : IPredicate { public bool Match(int target) => target < 100; } /// ///델리게이트로 구현하였을 때 /// public static IEnumerable Zip( IE..
Item 33 : 필요한 시점에 필요한 요소를 생성하라 이터레이터 메서드에 입력 매개변수로 굳이 시퀸스를 전달할 필요는 없다. 이터레이터 메서드 내에서 시퀸스를 생성하는 것도 나쁘지 않은 방법이다. 하지만 시퀸스를 생성하는 중간에 해당 시퀸스를 다른 부분에서 참조할 때 문제의 요소가 굉장히 많다. 또한 중간에 작업을 멈출 수도 없기 때문에 병목 현상이 발생할 수도 있다. 이런 시퀸스 생성 메서드를 이터레이터 함수로 구현한다면? 자연스럽게 해결될 것이다. //문제의 요소가 있는 메서드 static IList CreateSequence(int numberOfElements, int startAt, int stepBy) { var collection = new List(numberOfElements); for..
Item 32 : Action, Predicate, Function과 순회 방식을 분리하라 익명의 델리게이트를 사용할 때는 function과 action이라는 두 가지 패턴이 있다. predicate는 시퀸스 내의 항목이 조건에 부합하는지를 bool로 반환하는 function이다. predicate는 필터 메스드를 구현할 때 사용할 수 있다. public static IEnumerable Where( IEnumerable sequence, Predicate filterFunc) { if (sequence == null) throw new ArgumentNullException(nameof(sequence), "sequence must not be null"); if (filterFunc == null) ..