8

I am trying to figure out how to create an Expression that calls a method which has a reference parameter.

Let me explain my question with a simple (but artificial) example. Consider the method:

    public static int TwiceTheInput(int x)
    {
        return x*2;
    }

I can create an Expression to call the above method by doing something like:

    {
        var inputVar = Expression.Variable(typeof (int), "input");
        var blockExp =
            Expression.Block(
                    new[] {inputVar}
                    , Expression.Assign(inputVar, Expression.Constant(10))
                    , Expression.Assign(inputVar, Expression.Call(GetType().GetMethod("TwiceTheInput", new[] { typeof(int) }), inputVar))
                    , inputVar
                    );
        var result = Expression.Lambda<Func<int>>(blockExp).Compile()();
    }

On execution, the "result" above should end up with a value of 20. Now consider a version of TwiceTheInput() that uses by-reference parameters:

    public static void TwiceTheInputByRef(ref int x)
    {
        x = x * 2;
    }

How do I write a similar Expression Tree to call TwiceTheInputByRef() and pass arguments by reference to it?

Solution: (Thanks to Cicada). Use:

Type.MakeByRefType()

Here's a code segment to generate the Expression Tree:

        {
        var inputVar = Expression.Variable(typeof(int), "input");
        var blockExp =
            Expression.Block(
                    new[] { inputVar }
                    , Expression.Assign(inputVar, Expression.Constant(10))
                    , Expression.Call(GetType().GetMethod("TwiceTheInputByRef", new[] { typeof(int).MakeByRefType() }), inputVar)
                    , inputVar
                    );
        var result = Expression.Lambda<Func<int>>(blockExp).Compile()();
    }
2
  • 2
    Have you tried using a lambda expression to call the same method, getting the C# compiler to convert that to an expression tree, and then decompiling? That's normally what I do to work out how to build expression trees :) Commented Feb 18, 2013 at 15:55
  • No, I haven't done it before. Any url that walks through an example? Commented Feb 18, 2013 at 16:02

1 Answer 1

9

You don't have to change much, just remove the Assign and change typeof(int) to typeof(int).MakeByRefType().

var blockExp = Expression.Block(
    new[] { inputVar }
    , Expression.Assign(inputVar, Expression.Constant(10))
    , Expression.Call(
       typeof(Program).GetMethod( 
           "TwiceTheInputByRef", new [] { typeof(int).MakeByRefType() }),
       inputVar)
    , inputVar
);
Sign up to request clarification or add additional context in comments.

4 Comments

Don't recall off the top of my head, but could one use the (semi undocumented) __makeref keyword here? You'd need an actual variable, naturally.
@JerKimball As you said indeed, __makeref works on variables, not types, so we can't use it here. Note that the MakeByRefType part is just used by GetMethod to resolve the appropriate overload of TwiceTheInputByRef: if there's no overload, that second argument is superfluous.
Does Type.MakeByRefType() work equally well for both ref and out parameters? (It seems to work in a quick test that I tried..)
Yes, an out parameter is "by ref".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.