목록전체 글 (244)
방프리
1. 일정 시간동안 정지 - 간단한 딜레이 타임을 주는 정도의 기능 - 시나리오 코드 및 간단한 테스트 용도로 사용한다. (이외 실제 기능 혹은 배포에서는 들어가면 좋지 않은 코드) async Task DelayResult(T result, TimeSpan delay) { await Task.Delay(delay); return result; } // delay를 통한 soft timeout 기능 구현 async Task DownloadStringWithTimeout(HttpClient client, string url) { using var tokenSource= new CancellationTokenSource(TimeSpan.FromSecond(3)); Task downloadTask = clien..
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..
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)); // 해당 함수는 가상함수가 아니..