본문 바로가기

C#

[C#] Linq.Expression Snippets

원본 : https://github.com/pjc0247/LinqExpressionSnippets


LinqExpressionSnippets

System.Linq.Expression 네임스페이스 아래의 기능들에 대한 복붙용 코드 조각들.

Lambda를 Expression으로 전달받기

람다의 타입 판별

public static void Foo<T>(Expression<Func<T>> f)
{
    // Foo(() => Math.Abs(1));
    if (f.Body is MethodCallExpression)
        Console.WriteLine("MethodCallExpression");

    // Foo(() => pos.x);
    if (f.Body is MemberExpression)
        Console.WriteLine("MemberExpression");

    // Foo(() => 10);
    if (f.Body is ConstantExpression)
        Console.WriteLine("ConstExpression");

    // Foo(() => a > b);
    if (f.Body is BinaryExpression)
        Console.WriteLine("BinaryExpression");
}

MethodCallExpression

// Foo(() => Math.Abs(1));
if (f.Body is MethodCallExpression)
{
    var body = f.Body as MethodCallExpression;

    // System.Math
    Console.WriteLine(body.Method.DeclaringType);

    // Abs
    Console.WriteLine(body.Method.Name);

    // 1
    Console.WriteLine(body.Arguments[0]);
}

MemberExpression

// Foo(() => pos.x);
if (f.Body is MemberExpression)
{
    var body = f.Body as MemberExpression;

    // Vector2
    Console.WriteLine(body.Member.DeclaringType);

    var fieldExp = (MemberExpression)body.Expression;
    // pos
    Console.WriteLine(fieldExp.Member.Name);

    // System.Int32
    Console.WriteLine(body.Type);

    // x
    Console.WriteLine(body.Member.Name);
}

ConstantExpression

// Foo(() => 10);
if (f.Body is ConstantExpression)
{
    var body = f.Body as ConstantExpression;

    // System.Int32
    Console.WriteLine(body.Type);

    // 10
    Console.WriteLine(body.Value);
}

BinaryExpression

// Foo(() => a > b);
if (f.Body is BinaryExpression)
{
    var body = f.Body as BinaryExpression;

    // Expression
    Console.WriteLine(body.Left);
    // Expression
    Console.WriteLine(body.Right);

    // ExpressionType.GreaterThan
    Console.WriteLine(body.NodeType);
}

Exression 트리 생성하기

Hello World

var exp = Expression.Block(
    Expression.Call(
        null,
        typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
        Expression.Constant("Hello World")
    ));

var lambda = Expression.Lambda<Action>(exp);
lambda.Compile()();

local variables

var loc1 = Expression.Variable(typeof(int));
var loc2 = Expression.Variable(typeof(int));

var exp = Expression.Block(
    // 지역 변수 선언
    new ParameterExpression[] {
        loc1, loc2
    },

    // 메소드 바디
    Expression.Assign(
        loc1,
        Expression.Constant(10)),
    Expression.Call(
        null,
        typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }),
        loc1
    ));

var lambda = Expression.Lambda<Action>(exp);
lambda.Compile()();

If ~ Else

var loc1 = Expression.Variable(typeof(int));
var loc2 = Expression.Variable(typeof(int));

var exp = Expression.Block(
    // 지역 변수 선언
    new ParameterExpression[] {
        loc1, loc2
    },

    // 메소드 바디
    Expression.Assign(
        loc1,
        Expression.Constant(11)),

    Expression.IfThenElse(
        Expression.Equal(loc1, Expression.Constant(10)),

        Expression.Call(
            null,
            typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
            Expression.Constant("loc1 is 10")),

        Expression.Call(
            null,
            typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
            Expression.Constant("loc1 is not 10"))
    ));

var lambda = Expression.Lambda<Action>(exp);
lambda.Compile()();

트리 끼워넣기(Injection)

Before, After

static void Zoo(Expression<Action> f)
{
    var exp = Expression.Block(
        Expression.Call(
            null,
            typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
            Expression.Constant("before `f`")),

        f.Body,

        Expression.Call(
            null,
            typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
            Expression.Constant("after `f`"))
        );

    var lambda = Expression.Lambda<Action>(exp);
    lambda.Compile()();
}

트리 순회하기

static void Rini(Expression f)
{
    Console.WriteLine(f);

    if (f is MethodCallExpression)
    {
        var body = f as MethodCallExpression;

        foreach (var arg in body.Arguments)
            Rini(arg);
    }
    if (f is BinaryExpression)
    {
        var body = f as BinaryExpression;

        Rini(body.Left);
        Rini(body.Right);
    }
}
static void Rini(Expression<Action> f)
{
    Rini(f.Body);
}

Expression은 순회와, 수정에 적합한 구조는 아닙ㄴㅣ디ㅏ.

'C#' 카테고리의 다른 글

[C#] Async,Await의 내부  (0) 2016.08.29
[C#] async void / Task  (0) 2016.07.18
[HTTP] 웹소켓 핸드쉐이킹  (2) 2016.06.28
[C#] Mono 환경인지 구분하기  (0) 2016.06.21
[NUnit] Callback 방식의 API 테스트하기  (1) 2016.06.16