목록C#/Effective C# (50)
방프리
Item 26 : 제네릭 인터페이스와 논제네릭 인터페이스를 함께 구현하라 제네릭 타입은 C# 초기부터 있던 기능이 아니기 때문에 예전버전까지 호환해야한다면 이를 고려해야 한다. 세 가지 요소(클래스와 인터페이스, public 속성, Serialize)를 모두 지원해주어야 한다. 하단의 코드는 논제네릭 방식으로 구현된 (레거시 코드) Name 클래스이다. public class Name : IComparable, IEquatable { public string First { get; set; } public string Last { get; set; } public string Middle { get; set; } public int CompareTo(Name other) { if (Object.Refer..
Item 25 : 타입 매개변수로 인스턴스 필드를 만들 필요가 없다면 제네릭 메서드를 정의하라 저자는 제네릭을 사용할수록 개발자가 점점 실수를 할 수 있는 부분에 대해 염려한 것 같다. 이번 주제는 한마디로 줄이자면 편함을 버리자는 것이다. 아무 생각 없이 제네릭 클래스를 만드는 습관의 위험성인데 제네릭 클래스를 관리하다보면 제약조건이 점점 늘어날 수 있는데 그럴 경우마다 수정의 범위가 넓어진다. public static class Utils { public static T Max(T left, T right) => Comparer.Default.Compare(left, right) < 0 ? right : left; public static double Max(double left, double rig..
Item 24 : 베이스 클래스나 인터페이스에 대해서 제네릭을 특화하지 말라 제네릭 클래스나 제네릭 메서드를 작성할 때는 사용자가 가능한 한 안전하고 혼란스럽지 않게 작성해야야한다. 특히 오버로드된 메서드가 여러 개인 경우, 컴파일러가 어떤 메서드를 선택하는지 정확히 알아야한다. 다음 예제를 통해서 어떤 메서드를 우선으로 호출하는지 확인해볼 수 있다. using static System.Console; public class MyBase { } public interface IMessageWriter { void WriteMessage(); } public class MyDerived : MyBase, IMessageWriter { void IMessageWriter.WriteMessage() => Wr..
Item 23 : 타입 매개변수에 대해 메서드 제약 조건을 설정하려면 델리게이트를 활용하라. 특정 행위를 하는 클래스를 생성할 때 메서드를 이용하기보다는 델리게이트로 구현하는 방법이 더 효율적인 경우가 있다. 예로 캐릭터들의 이동이라는 함수를 만들 때 모든 캐릭터들은 이동을 하기 때문에 IMove라는 인터페이스를 만든 후 구현하는 것이 보편적이다. 하지만 Move()라는 메서드를 호출하기 위해 IMove 인터페이스를 만들고 그것을 상속하고... 작업량이 굉장히 많아진다. 하지만 이 메서드를 생성하는 방식 대신에 델리게이트를 이용한다면 굳이 인터페이스를 생성하지 않고 불필요한 작업량을 줄일 수 있다 (= 코드 양을 줄일 수 있다.) public static class ReplaceInterface { pu..
Item 22 : 공변성과 반공변성을 지원하라 공변성과 반공변성은 무엇일까? 단어부터 생소하다. 타입의 가변성으로도 말하는데 특정 타입의 객체를 다른 타입의 객체로 변환할 수 있는 성격을 말한다. abctract public class CelestialBody : IComparable { public double Mass { get; set; } public string Name { get; set; } } public class Planet : CelestialBody { } public class Moon : CelestialBody { } public class Asteroid : CelestialBody { } [예제에 사용될 클래스들] 공변성 X를 Y로 바꾸어 사용할 수 있는 경우, C를 C로도..

Item 21 : 타입 매개변수가 IDisposable을 구현한 경우를 대비하여 제네릭 클래스를 작성하라 제약조건은 두 가지 역할을 한다. (1) 런타임 오류가 발생할 가능성이 있는 부분을 컴파일 타임 오류로 대체 (2) 타입 매개변수로 사용할 수 있는 타입을 명확히 규정하여 사용자에게 도움 하지만 타입 매개변수로 지정된 타입이 제약 조건을 통해 요구하는 작업 외에 다른 작업을 추가로 수행할 수 있는지에 대해서는 신경쓰지 않는다. 하단의 코드는 제네릭 메서드 내에서 타입 매개변수로 주어지는 타입을 이용해 인스턴스를 생성할 때의 처리다. using 구문을 통해 해당 타입에 IDisposable이 구현되어 있는지 확인 후 해당 함수를 실행시키는 것이다. (쉽게 생각해서 null 체크를 한 것이다.) 함수가 ..

Item 20: IComparable와 IComparer를 이용하여 객체의 선후 관계를 정의하라 앞에서의 Enumerable과 같이 인터페이스를 통해 Compare를 구현할 수 있다. 이 IComparable는 CompareTo()라는 메서드 하나만을 정의하고 있는데 이 함수는 C 라이브러리의 strcmp 함수의 구현방식을 그대로 따르고 있다. .NET 환경에서 최신 API들은 IComparable를 사용하지만, .Net Framework 2.0이하에서는 object 타입을 받는 IComparable을 사용하고 있기 때문에 두 가지를 같이 구현해주어야 한다. 하지만 위의 코드는 object 타입을 받기 때문에 연산량이 굉장히 많아진다. (박싱과 언박싱) 위의 코드에서는 선후 관계를 명시된 타입으로 재정의..