목록C# (122)
방프리
Item 47 : 사용자 지정 예외 클래스를 완벽하게 작성하라 예외처리는 프로그래머라면 반드시 해주어야 하는 필수항목이다. 예외를 처리할 때 Exception 클래스를 통해 통합적인 예외처리를 하는 방법과 NullReferenceException 같은 특수 Exception 클래스를 인자로 예외처리 하는 두 가지 방식으로 나뉜다. 이 항목에서 저자는 전자가 아닌 후자로 처리하되 자신이 만든 클래스 타입에서 예외 처리를 해야한다면 반드시 그 클래스에 맞는 예외 클래스도 만들어주어야 한다고 강조한다. //모든 예외를 처리할 수 있지만 정확한 원인 파악이 어려움 try { DoWork(); } catch (Exception e) { CatchException(); } finally { LastWork(); }..
Item 46 : 리소스 정리를 위해 using과 try/finally를 활용하라 C에는 malloc과 free, C++에 new, delete가 있다면 C#에는 new, Dispose()가 있다. C#에서는 가비지 컬렉터에서 어느 정도 리소스를 자동으로 해제해주기 때문에 큰 리소스를 관리하지 않는 이상 Dispose()를 사용할 일이 크게 없다. 만약 사용하게 된다면 반드시 IDisposable 인터페이스를 구현해주어야 한다. 하지만 많은 사람들은 직접 Dispose() 하는 것을 그렇게 추천하지 않는다. 아무래도 자동으로 메모리를 해제하는 동작에 최대한 간섭을 주지 않게 하기 위해서인 것 같다. 만약 사용하게 된다면 일일히 delete처럼 Dispose()를 사용해주어야 하는데, 이를 좀 더 간편하게..
Item 45 : 메서드가 실패했음을 알리기 위해서 예외를 사용하라 개발자라면 예외처리는 항상 유념해두어야 하는 항목 중 하나이다. 그리고 예외처리라고 하면 가장 먼저 떠오르는 것은 바로 try/catch 일 것이다. 하지만 해당 주제에서 저자는 try/catch 뿐만이 아닌 메서드의 분할을 통해서 좀 더 세밀하게 예외 처리하는 방식을 추천하고 있다. public class DoesWorkThatMightFail { public bool TryDoWork() { if (!TestConditions()) return false; Work(); return true; } public void DoWork() { Work(); } private bool TestConditions() { return true;..
Item 44 : 바인딩된 변수는 수정하지 말라 이번에도 클로저를 사용했을 때의 경우 유의해야하는 부분이다. 쿼리문을 실행하면서 지역 변수라든지 이미 클로저에서 캡쳐된 변수를 수정하는 코드를 넣을 수도 있는데 이는 컴파일러가 어떻게 동작을 할 것인지 결정에 따라 동작 방식이 크게 차이가 난다. public class ModFilter { private readonly int modulus; public ModFilter(int mod) { modulus = mod; } public IEnumerable FindValues(IEnumerable sequence) { int numValues = 0; return from n in sequence where n % modulus == 0 select n * ..
Item 43 : 쿼리 결과의 의미를 명확히 강제하고, Single()과 First()를 사용하라 쿼리를 통해서 데이터를 가져오는 방법은 여러가지가 있다. ToList(), ToArray() 등을 통해 시퀸스 형식을 가져오는 방법과 Single(), First() 등을 통해 단일 요소를 가져오는 방법으로 나뉜다. 이 중 단일 요소를 가져올 때 Single()과 First()의 차이를 유의해야한다. 간단하게 쿼리문을 통해 얻고자 하는 데이터가 무조건 하나일 경우 Single(), 여러 개가 있을 경우에는 First()를 사용하면 된다. //Index가 기본키라고 할 때 기본키는 해당 테이블에서 하나만 존재할 수 있으므로 var singleElement = dbContext.MyTable.Where(p =>..
Item 42 : IEnumerable 데이터 소스와 IQueryable 데이터 소스를 구분하라 IQueryable와 IEnumerable는 시퀸스 성향을 띈다는 점에서 비슷해보이지만, 실제로는 굉장히 많이 다르다. IQueryable는 특히 쿼리문 처리에서 뛰어난 성능을 보인다. Enumerable 확장 메서듣는 쿼리식 내의 람다 표현식과 함수 매개변수를 나타내기 위해서 델리게이트를 사용하고, Queryable는 동일한 함수라 하더라도 표현식 트리를 이용하여 처리한다. 특히 로직의 처리를 Enumerable는 해당 로직이 실행되는 곳에서 처리하고, Queryable를 로직을 분석하여 실제 데이터가 있는 Database 혹은 장비에서 직접 처리 후 결과값을 가져오도록 한다. Queryable는 이름에 맞..
Item 41 : 값비싼 리소스를 캡처하지 말라 처음으로 C#에서 클로저라는 단어를 들었다. Swift에서 사용되는 클로저와 비슷한 느낌인데 간단히 풀어서 람다 표현식이 동작하는 메서드의 지역변수를 람다 표현식에서 사용하면 클로저라고 한다. 클로저는 예시로 보는게 더 이해가 쉬울 것 같다. public void DoSomething() { int localVariable = 0; Action operatorLambda = delegate(int value) { int result = localVariable + value; } } 이 클로저는 대표적으로 LINQ에서 자주 사용된다고 한다. 해당 주제는 이 클로저를 사용할 때 문제가 발생하는 것에 대해 지적한다. 보통 개발자들은 로직을 만들 때 지역변수는 ..
Item 40 : 지연 수행과 즉시 수행을 구분하라 이전 37번 항목 (쿼리를 사용할 때는 즉시 평가보다 지연 평가가 낫다)에서 LINQ에서 지연 수행의 필요성을 배웠었다. 이번 항목도 이에 대한 연장선이라고 할 수 있다. 보통 다음의 코드를 본다면 다음과 같이 동작할거라 생각한다. var answer = DoStuff( () => Method1(), () => Method2(), () => Method3()); // Method1() => Method2() => Method3() 하지만 그렇지 않다. DoStuff()가 수행되면서 필요할 때만 해당 함수를 수행하게 된다. 즉 Method2()가 실행 될 때 이미 Method1()이 실행된 상태가 아니라는 뜻이다. 특히 예제에서는 매개변수가 없지만, 매개..