0

Ok, here is the problem:

int a = 111;
int b = 222;

Expression<Func<int>> expr = ()=> someClass.SomeWork(a) + b + 1;

As you see, there is 3 different arguments: someClass, a, b. They are all from another scope of execution, but one isn't. How I can get them? I mean, in general, I want only variables of outter scope.

For example, I want to use it like this:

var result = InvokeAndLog(expr);//this will invoke expression and print out everything I need from these arguments.
eocron
  • 6,885
  • 1
  • 21
  • 50
  • You have to compile the expression before you can use it using `expr.Compile()`. Now you can simply call the returned `Func` as with any other delegate. – MakePeaceGreatAgain Nov 03 '16 at 06:47
  • I don't think that the question is about how to compile and execute this expression. – Zoltán Tamási Nov 03 '16 at 06:53
  • If you want to parse the expression to find the referenced variables, take a look at this, it might give some hints http://stackoverflow.com/questions/7220626/local-variable-and-expression-trees – Zoltán Tamási Nov 03 '16 at 06:54

1 Answers1

0

Ok, folks, I found answer myself. And here it is:

internal class Program
{
    public static int Method1()
    {
        return new Random(0).Next(10000);
    }

    public class MyClass
    {
        private int var = 11111;

        public int GetSome(int val)
        {
            return var * val;
        }
    }

    private static void Main()
    {

        var clas = new MyClass();
        int a = 111;
        int b = 222;
        Expression<Func<int>> expr = () => a * 2 - clas.GetSome(b) + b + 1 - Method1();
        var result = InvokeAndLog(expr);
    }

    private static T InvokeAndLog<T>(Expression<Func<T>> expr)
    {
        var visitor = new ArgumentsVisitor();
        visitor.Visit(expr);
        Console.WriteLine("Inputs: {0}", string.Join(", ", visitor.Arguments));
        return expr.Compile()();
    }
}

The main class here is ExpressionVisitor descendant. I just overrided its member visitor and aggregated all members into single set:

    public class ArgumentsVisitor : ExpressionVisitor
    {
        private readonly HashSet<MemberInfo> _all = new HashSet<MemberInfo>();

        public IEnumerable<MemberInfo> Arguments
        {
            get { return _all; }
        }

        protected override Expression VisitMember(MemberExpression node)
        {
            _all.Add(node.Member);
            return base.VisitMember(node);
        }
    }

Then I applyed visitor to expression and printed out all variables! Thanks, microsoft =)

eocron
  • 6,885
  • 1
  • 21
  • 50
  • Okay, I get what you want, but I can´t see any reason not to provide the args that your delegate actually *needs* by its signature but by relying on the outer scope of where the delegate is defined, This seems like a bad design to me and thus you need those dirty hacks to get the attributes. – MakePeaceGreatAgain Nov 03 '16 at 07:16
  • I prefer not to use them at all. But It's real world, with legacy problems. To see what happens without duplication - you need to do some inspection of 1000 of functions. If all were built without hacks, hacks won't be needed in the first place. – eocron Nov 03 '16 at 07:18
  • This seems to be quite important information to me needed within the question to get good answers, Obviously unclear questions result in not-helpful answers. – MakePeaceGreatAgain Nov 03 '16 at 07:20