목록C#/More Effective C# (48)
방프리
Item 24 : 설계 선택지를 제한하는 ICloneable은 사용을 피하라 복사를 지원해야하는 타입에서 ICloneable은 좋은 선택지이다. 하지만 해당 타입이 상속 계통상에 있는 타입이라면? 조금 사용하는 것에 있어서 고려를 해보아야 한다. 타입의 멤버가 값타입이라면 ICloneable을 지원할 필요가 없다. ICloneable에 있는 Clone()은 object 형태이기 때문에 박싱 언박싱으로 인해 연산량이 더 오래 걸려 굳이 사용할 필요가 없다. 하지만 string과 같은 참조 타입이 있을 경우 Clone()을 사용하게 되는데 이때에도 깊은 복사를 지원하는지 살펴볼 필요가 있다. 만약 파생 계층에 있는 타입에서 ICloneable을 지원하게 한다면 모든 파생 클래스들에서 Clone()을 구현해야..
Item 23 : 생성자, 변경자, 이벤트 핸들러를 위해 partial 클래스와 메서드를 제공하라 C#에서는 UI와 코드를 분리하기 위해서 partial이라는 키워드를 생성했다. 이로인해 디자이너와 개발자의 영역을 확실히 구분되었다. (각 부분에서 문제가 생기면 자기가 맡은 영역만 확인) C# 3.0 버전에서는 기본 partial에서 새로운 기능을 추가하였는데 바로 partial 메서드이다. 간단히 설명하자면 기본 partial 클래스의 역할에서 조금 더 세분화되어 구현영역과 선언영역을 분리했다고 보면 좋을 것 같다. (처음 예제를 보고 C++의 .h 와 .cpp 의 구조를 보는 듯 했다.) 대신 struct, class, interface와 달리 partial method를 선언할 때에는 약간의 제약이..
Item 22 : 명확하고 간결하며 완결된 메서드 그룹을 생성하라 API를 구성할 때 유의해야할 점이 사용하는 사람이 보았을 때 혼동이 있어서는 안된다. 명확하고 사용자가 API를 사용함으로써 실수를 줄일 수 있는 몇 가지 방법이 있다. 1. 적은 양의 오버로드 함수 - 오버로드된 함수를 만드는 것은 좋으나, 그 개수가 많아진다면 사용자 측면에서 혼동이 일어날 수 있다. 나중에는 각 함수 별 각주를 달거나 사용자가 해당 API를 사용할 때마다 기능을 확인해야 하는 경우가 발생할 수 있으니 무분별한 오버로드 함수는 좋지 않다. 2. 동일 명에 동일 동작이 원칙 - 같은 메서드 명이라면 그 안에서 동작하는 행위는 무조건 같아야 한다. 다를 경우 사용자 측면에서 구분하기 어렵고 사용 시 예측 불가능한 동작이 ..
Item 21 : 이벤트는 가상으로 선언하지 말라 이벤트를 가상으로 선언할 경우 결합도가 더 강해진다. 가상으로 선언할 경우 파생 클래스에서만 사용 가능하거나 베이스 클래스에서만 사용 가능한 선택 영역으로 빠지기 때문이다. 결합도를 낮추기 위해 사용했던 것이 오히려 결합도를 강하게 만들어버린 상황이 오게 된다. 이 경우 저자는 두 가지 해결책을 제시하였다. 1. 가상 이벤트를 만들 때 필드 정의 방식으로 이벤트를 정의하지 않는 것 2. 가상 이벤트 정의를 생성할 때마다 이벤트를 발생시키는 가상 메서드를 만드는 것 하단의 코드는 2번 해결책을 응용한 코드이다. public abstract class WorkerEngineBase { public virtual event EventHandler OnProgr..
Item 20 : 이벤트가 런타임 시 객체 간의 결합도를 증가시킨다는 것을 이해하라 이벤트는 구독자를 통해서 한 번에 여러 동작을 동시에 할 수 있다는 점에서 굉장히 유용하다 하지만 이는 자칫 잘 못 사용하면 하나의 이벤트에 여러 구독자가 뒤섞이면서 관리 차원에서 문제가 발생할 수도 있다는 뜻이다. 특히 런타임 때 이벤트 구독이 엮인다면? Dispose될 때 처리까지 완벽하게 이루어져야 한다. 개발자가 어느 이벤트를 구독시킬건지만 명확하게 한다면?, 또는 하나의 이벤트에 하나의 구독자만 구독하게 규칙을 정한다면 굉장히 유용할 것 같다. 다만... 런타임 때 이벤트 구독을 시키는 것은 Dispose처리를 명확하게 할 수 있거나 그 시점을 명확하게 조절할 수 있다면 사용해도 무방할 것 같다. (ex. 싱글톤..
Item 19 : 베이스 클래스에 정의된 메서드를 오버로드해서는 안 된다. 베이스 클래스와 파생 클래스 간에 오버로딩이 미치는 영향은 매개변수의 타입에 영향을 받는다. 즉 어떤 매개변수를 전달하느냐에 따라 예상치 못한 결과가 나올 수 있다. 오버로드는 다음과 같은 규칙을 가지고 있다. 1. 컴파일 타임상 상속 계통의 가장 아래쪽에 위치한 클래스의 메서드가 호출 가능한 메서드가 있는 경우 해당 메서드 선택 2. 런타임 타입이 파생 클래스일지라도 컴파일타임 타입이 베이스 클래스라면 베이스 클래스의 메서드 호출 3. 제네릭 방식의 매개변수를 추가할 경우 C# 버전에 따라 다른 결과를 도출 public class Animal { public void Foo(Apple parm) => WriteLine("In A..
Item 18 : 이벤트 핸들러보다는 오버라이딩을 사용하라 해당 항목은 기본적으로 제공해주는 가상 메서드가 있을 경우 (ex. WPF의 버튼 클릭, Unity UI Event 의 OnDrag) 에 적용되는 항목인 것 같다. 쉽게 말해 이벤트 핸들러를 통해 기능을 구현하려고 할 경우 오버라이딩으로 구현하였을 때 문제점이 발생하면 쉽게 찾을 수 있으며, 디자인적으로도 분리가 쉽다. 하지만 이벤트 핸들러로 구현하였을 땐 핸들러에 등록된 모든 이벤트를 확인해야할 뿐만 아니라 어떻게 구현하였느냐에 따라 핸들러에 등록된 이벤트가 추가 혹은 삭제가 될 수 있으므로 추적이 힘들다. 추가로 디자인적으로 맞물리지 않아 디자이너가 선작업 후 프로그래머가 다시 손을 대야 하는 단점이 있다. (한 마디로 구현되어 있는거 사용하..
Item 17 : 내부 객체를 참조로 반환해서는 안된다. 내부 객체를 외부에 노출시킬 때 다음과 같은 실수를 많이 할 것 같다. public class MyBusinessObject { public MyBusinessObject() { DAta = new BindingList(); } public BindingList Data { get; } } BindingList stuff = bizObj.Data; stuff.Clear(); 프로퍼티를 통해 getter만 활성하였으나 참조 형태로 반환하여 원본 데이터가 훼손될 여지를 주게 되는 것이다. 어떻게 하면 외부의 동작으로부터 내부의 데이터를 보호할 수 있을까? 외부에 노출시킬 때 원본이 아닌 복사 객체를 보여주는 것이다. public class MyBusi..