목록C# (122)
방프리
Item 47 : Public API에서는 동적 객체 사용을 최소화하라dynamic 객체는 건드리는 모든 것을 동적으로 만들어버리기에 사용 시 매우 주의해야 한다. 작업의 대상이 되는 매개 변수 중 하나라도 dynamic이라면 그 결과도 dynamic이 된다. 또한 메서드가 동적 객체를 반환하면 그 객체를 사용하는 모든 것이 동적 객체가 된다.C#은 기본적으로 정적 타입을 선호하며 일부 영역에 동적 타이핑을 적용한다는 점을 반드시 알고 있어야 한다. 만약 주 타이핑 방식이 동적으로만 이루어진다면 언어 선택에 대한 의구심을 가질 필요가 있다. 동적 프로그래밍은 취지는 좋으나 특성상 런타임에 리소스를 많이 사용해야 한다는 점을 알고 있어야 한다. 또한 public 인터페이스에서는 가능한 제외되어야 한다. 동..
Item 43 : 동적 타이핑의 장단점을 이해하라dynamic 타입은 '런타임에 바인딩되는 System.Object'.라고 볼 수 있다. 따라서 컴파일타임에 dynamic 타입의 변수는 System.Object에 정의된 메서드만 가지고 있다. 런타임 시 객체의 타입을 확인하고, 수행할 메서드가 지원되는지 확인한다. 이 방식을 덕 타이핑이라고 부른다. 이 방식은 특별히 인터페이스를 선언하거나, 커파일타임 타입 연산을 제공할 필요가 없다. 동적 타이핑은 타입에 대한 대처를 유연하게 할 수 있지만 타입 안정성을 고려하지 않으며 컴파일러가 도와줄 수 있는 범위가 한정적이기에 오류를 런타임에 찾을 수 있다는 단점이 있다.표현식 트리는 런타임에 코드를 구성하는 방법 중 하나인데 System.Linq.Expressi..
Item 46 : 표현식 API의 사용법을 익혀두라C#에 LINQ와 동적 지원 기능이 추가되면서 표현식과 표현식 트리를 사용해 동적 프로그래밍이 가능하다.표현식은 코드처럼 보이며 많은 경우 델리게이트로 컴파일하여 사용한다.표현식을 사용하게되면 여러 제약조건으로 메서드를 사용할 때 코드량을 줄이면서 유연하게 사용이 가능하다.public TResult CallInterface(Expression> op){ var exp = op.Body as MethodCallExpression; var methodName = exp.Method.Name; var methodInfo = exp.Method; var allParameters = from element in exp.Arguments ..
Item 45 : 데이터 주도 동적 타입에는 DynamicObject나 IDynamicMetaObjectProvider를 사용하라동적 프로그래밍의 큰 장점 하나는 런타임에 public 인터페이스가 바뀌는 타입을 만들 수 있다는 것이다. C#에서는 dynamic과 System.Dynamic.DynamicObject 베이스 클래스 그리고 System.Dynamic.IDynamicMetaObjectProvider 인터페이스를 통해 동적 능력을 갖춘 고유의 타입을 만들 수 있다.동적 능력을 가지는 타입을 만드는 다음과 같다.1. System.Dynamic.DynamicObject 상속- 가장 구현이 쉬운 방법 이 타입은 IDynamicMetaObjectProvider 인터페이스를 구현한 중첩 private 클래..
Item 44 : 동적 타이핑의 장단점을 이해하라Cast는 제네릭 메서드로, T타입으로 타입 변환이 가능하기만 하다면 어떤 타입이든 사용할 수 있다. 하지만 Cast의 한계에 대해서 제대로 알지 못하면 예상대로 동작하지 않기에 제대로 알고 사용해야한다.// 동작되지 않는 코드var answer1 = GetSomeStrings().Cast();try{ foreach (var v in answer1) WriteLine(v);}catch (INvalidCastException){ WriteLine("Cast Failed!");}Cast는 인수 런타임 타입에서 제공하는 사용자 정의 변환 함수에는 접근할 수 없다. 단순히 참조 변환가 박싱 변환만 가능하기에 Cast는 T가 System.Ob..
Item 42 : 잠김 영역에서는 외부 코드 호출을 삼가라lock을 통해 보호하는 영역 내에서 리스너를 통해 함수를 호출하는 방식은 교착상태를 불러 일으킬 수 있다.public class WorkerClass{ public event EventHandler RaiseProgress; private object syncHandle = new object(); public void DoWork() { for (int count = 0; count 위와 같이 코드를 작성하였을 때 Progress 객체에 접근할 때와 engine_RaiseProgress 함수를 호출할 때 교착상태가 발생할 확률이 매우 크다. 이 문제는 아래와 같이 수정하여 회피하는 것이 좋다...
Item 41 : 락은 가능한 한 좁은 법위에 적용하라 private 접근제한자를 통해 멤버 변수를 관리할 범위를 최소화하는 것처럼 lock 또한 최소 단위로 관리해야 한다. 필자는 lock을 관리하는 총 3가지 방식을 제안한다 1. MethodImplAttribute를 사용해서 메서드 전체를 보호한다. 가장 드물게 사용 [MethodImpl(MethodImplOptions.Synchronized)] public void IncrementTotal() { total++; } 2. 개발자에게 현재 타입이나 현재 객체에만 락을 걸도록 의무화한다. 즉, 모두가 lock(this)나 lock(MyType)을 사용하도록 권장한다. 하지만 위의 방식은 전 세계 개발자 모두가 가이드를 지켜야 하므로 수행되기 어려움 ..
Item 40 : 동기화에는 lock()을 최우선으로 사용하라 동기화 요소는 특정 스레드가 임계영역 내에서 연산을 수행하는 동안 다른 스레드로부터 이를 보호하는 역할을 수행한다. .NET 기본 클래스 라이브러리에서는 다양한 기능을 통해 공유 데이터에 대한 접근을 안전하게 동기화하는데 특히 Monitor.Enter()와 Monitor.Exit()는 특별하게 다루어진다. 하지만 lock()이 가장 기본이 되는 기능이므로 최우선적으로 고려 시에는 lock()을 먼저 사용하는 것이 좋다. lock()은 값 타입을 지원하지 않는다. 그러기에 Monitor.Enter()을 사용하게 되는데 이 때 주의할 점이 있다. 하단의 코드는 정상적으로 컴파일은 되지만 문제가 발생할 수 있다. public void Increme..