목록C#/More Effective C# (48)
방프리
Item 16 : 상태 전달을 위한 이벤트 패턴을 구현하라 이벤트와 델리게이트를 설명할 때 자주 묶지만 둘은 엄연히 다르다. 어떤 타입이 시스템의 변화에 대해서 다수의 클라이언트와 상호작용해야 한다면 이벤트를 활용하는 것이 좋다. 또한 이벤트는 실행 시 멀티 스레드로부터 안전하다. 하단의 코드는 특정 이벤트가 발생 시 로그를 작성하는 클래스이다. class EventLogger { private static Logger logger = Logger.Singleton; private static string eventSource; private static EventLog logDest; static EventLogger() => logger.Log += (sender, msg) => { logDest?...
Item 15 : 인터페이스 메서드와 가상 메서드의 차이를 이해하라 인터페이스와 가상 함수를 재정의하는 건 확실히 다르다. 가상 함수는 필수적으로 구현해주어야 하지만 인터페이스 함수는 그렇지 않기 때문이다. 각각의 방식을 사용한 코드는 다음과 같다. //인터페이스 interface IMessage { void Message(); } public class MyClass : IMessage { public void Message() => WriteLine(nameof(MyClass)); } public class MyDerivedClass : MyClass { public new void Message() => WriteLine(nameof(MyDerivedClass)); // 해당 함수는 가상함수가 아니..
Item 14 : 상속보다는 인터페이스를 정의하고 구현하는 것이 낫다. 재설계를 고려하면서 데이터 모델을 정의할 때 항상 기로에 놓인다. 추상 베이스 클래스를 작성해야 하나? 아니면 인터페이스를 정의하는게 좋을까? 필자는 인터페이스에 메서드를 정의하게 되면 해당 인터페이스를 사용하는 모든 클래스들에서 구현을 필수로 해주어야 하고(강제성), 서로 연관이 없는 타입이라 하더라도 동일한 인터페이스를 사용한다면 동일하게 사용할 수 있다는 점에서 인터페이스 구현을 좀 더 적극적으로 추천한다. 물론 이 두 방식 중 어떤 걸 진행하느냐는 해당 클래스의 설계 방식에 따라 장, 단점이 나뉘지만 적어도 명확하게 메서드의 동작방식이 정해져야 하는 모델이라면 메서드를 추가하더라도 암묵적으로 허용하는 추상 클래스 대신 컴파일 ..
Item 13 : 타입의 가시성을 제한하라 함수나 클래스를 생성할 때 쓸데없는 public 사용 남발을 주의해야 한다. 클린 코드란 책에서도 언급하지만 무분별한 public의 사용은 보안상에도 그다지 좋지 않고 다른 개발자들에게 라이브러리로 제공되었을 때 혼선을 주기가 쉽다. 때에 따라 private/protect/public을 골라쓰되 internal도 굉장히 좋으니 사용하길 권한다.
Item 12 : API에는 변환 연산자를 작성하지 말라 함수를 만들다보면 같은 동작을 하는 함수임에도 매개변수가 무한히 늘어나게 되는 함수를 볼 수 있다. 이를 위해 C에서는 ..., C#에서는 params를 통해서 해결하지만 이 챕터에서는 다른 방향을 제시한다. /////////////////////////////////////////////////변경하기 전 매개변수가 쓸데없이 늘어나는 코드 var wasted = Type.Missing; var wordApp = new Microsoft.Office.Interop.Word.Application(); wordApp.Visible = true; Documents docs = wordApp.Documents; Document doc = docs.Add(..
Item 11 : API에는 변환 연산자를 작성하지 말라 처음 객체지향을 배울 때 상속이라는 개념을 배운다. 이를 토대로 C#에서는 모든 데이터 타입은 System.Object 타입을 상속받고 있다. 보통 상속이라는 개념을 설명할 때에는 도형을 자주 빗대어 설명한다. public class Circle : Shape { private Point center; private double radius; public Circle() : this(new Point(), 0) { } public Circle(Point c, double r) { center = c; radius = r; } public override void Draw() { //... } static public implicit operator..
Item 10 : GetHashCode()의 위험성을 이해하라 GetHashCode()는 해시 기반 컬렉션에서 키의 해시값을 정의할 때에만 사용된다. HashCode는 변경 불가능한 값(Database의 Primary Key라 생각하면 쉬울 것 같다.)을 사용해야 하나, 제일 좋은 방법은 GetHashCode() 자체를 사용하지 않는 것이다. 하지만 부득이하게 사용해야할 경우 다음 세 가지 규칙을 따라 사용하는 것이 좋다. 1. 두 객체가 같다면(Equals() 인스턴스 메서드로 비교 시) 동일한 해시값을 생성해야 한다. 그렇지 않으면 컬렉션에서 객체를 찾는 데 해시 코드를 사용할 수 없다. 2. 모든 객체 a에 대해 a.GetHashCode()는 인스턴스 불변이어야 한다. a의 어떤 메서등를 호출하였든..
Item 9 : 다양한 동일성 개념들 사이의 상관관계를 이해하라 public static bool ReferenceEquals(object left, object right); public static bool Equals(object left, object right); public virtual bool Equals(object right); public static bool operator ==(MyClass left, MyClass right); 객체가 동일한지 비교할 때 위의 함수들을 사용할 수 있고, 각 함수들은 재정의될 수 있다. 또한 IEquatable와 IStructuralEquality를 통해 동일성을 재정의할 수 있다. 하지만 무작정 모든 함수를 재정의해서는 안된다. 위의 정적 함수인..