[More Effective C#] 5장 - Item 46: 표현식 API의 사용법을 익혀두라

SY·2023년 11월 15일

More Effective C#

목록 보기
45/46
post-thumbnail

빌 와그너, ⌜More Effective C# 2판⌟, 김완섭 옮김, 한빛미디어, 2019
이 포스팅은 ⌜More Effective C# 2판⌟의 내용을 기반으로 작성되었습니다.


아이템 46: 표현식 API의 사용법을 익혀두라



C#에 LINQ와 동적 지원 기능이 추가되어 이전에 리플렉션 API를 사용할 때보다 더 좋은 표현식, 표현식 트리선택지가 생겼다.


표현식을 통해 쉽게 해결할 수 있는 문제들


1. 표현식을 파싱해서 코드(또는 코드 정의 표현식)를 데이터 요소(런타임 알고리즘 구현에 사용할)로 변환하는 방법

커뮤니케이션 프레임워크에서 발생하는 문제와 같은 경우를 해결해준다.

  • 호출자 코드 예시
var client = new ClientProxy<IService>();
var result = client.CallInterface<string>(srver => srver.DoWork(172));

ClientProxy<T>는 실제로 접근하는 서비스를 몰라도, 인수에 따라 적절한 메서드 호출로 연결해 준다.

CallInterface() 함수에서 사용한 MethodCallExpression은 모든 매개변수와 호출되는 메서드 이름을 이해하는데 필요한 정보를 모두 가지고 있다..

  • CallInterface() 코드 예시
public TResult CallInterface<TResult>(Expression<Func<T, TResult>> op)
{
	var exp = op.Body as MethodCallExpression;
    var methodName = exp.Method.Name;
    var allParameters = from element in exp.Arguments
    					select processArgument(element);
                        
    // 코드 생략
    
    return default(TResult);
}

위의 호출자 코드를 아래와 같이 수정하여,
표현식 트리를 이용해서 사용자가 실행하고자 하는 코드를 런타임에 결정할 수 있다.

  • 호출자 코드 예시
client.Callinterface(srver => srver.DoWork(
	client.Callinterface(srv => srv.GetANumber())));


2. 런타임에 코드를 생성하는 방법

1번과 반대된다.
대규모 시스템에서는 원본 타입을 이용하여 대상타입의 객체를 생성하는 것과 연관된 문제를 해결해야 할 경우가 있다.

타입 변환 메서드를 만들면 타입의 속성의 이름이 모두 동일하고, 원본 객체에 public get, 대상 객체에 public set 접근자가 있어야 한다.



그 경우에 타입을 변환하는 메서드를 일일히 작성하는 대신, 필요한 구현체를 알아낼 수 있는 타입을 만드는 코드를 작성할 수 있다.
런타임에 코드를 생성해야 하는 작업을 가장 잘 다루는 것은 표현식을 생성해서 컴파일하고 실행하는 것이다.



표현식 트리를 만들기 위해 매개 변수를 선언한다.

  • 매개변수 선언 예시 코드
var source = Expression.Parameter(typeof(TSource), "source");

그 다음 원본 객체의 속성을 대상에 할당한다.

List<Expression>을 만들어 문장을 구성하는 모든 표현식을 담은 배열을 만든다.
마지막으로, 지금까지 만든 모든 구문을 표현하는 람다 표현식을 생성한다.

  • 람다 표현식 예시 코드
var expr =
	Expression.Lambda<Func<TSource, TDest>>(
    	Expression.Block(
        	new[] { dest }, // 표현식 매개변수
            	body.ToArray() //몸체
                ),
            source // 람다 표현식
    );

Block()은 모든 표현식을 담은 배열을 요구한다.

이후 코드 컴파일하여 호출 가능한 델리게이트로 변환한다.

var func = expr.Compile();
converter = func;


표현식 API는 두 가지 다른 방식으로 사용할 수 있다.

  • 표현식을 매개변수로 취하는 메서드를 만드는 것
    • 표현식을 파싱해서 해당 표현식의 개념을 코드로 생성할 수 있다.
  • 런타임에 코드를 생성하는 것
    • 코드를 작성하는 클래스를 생성, 실행하는 방법
profile
게임 개발 공부

0개의 댓글