5

is it possible to create an anonymous method in c# from a string?

e.g. if I have a string "x + y * z" is it possible to turn this into some sort of method/lambda object that I can call with arbitrary x,y,z parameters?

3
  • I am pretty sure some guy at microsoft did a broadcast about .net 4 having compiler available as a service to accomplish things like this. Don't know if it's your case though. Commented Oct 15, 2009 at 20:57
  • 1
    Anders was talking about very far-future work when he was talking about "compiler as a service" at PDC. C# 4 will certainly have no such work. Commented Oct 15, 2009 at 22:05
  • 1
    Duplicate: stackoverflow.com/questions/1437964/… That question was also answered more specifically than this one was. Commented Oct 19, 2009 at 10:40

5 Answers 5

14

It's possible, yes. You have to parse the string and, for example, compile a delegate using expression trees.

Here's an example of creating (x, y, z) => x + y * z using expression trees:

ParameterExpression parameterX = Expression.Parameter(typeof(int), "x");
ParameterExpression parameterY = Expression.Parameter(typeof(int), "y");
ParameterExpression parameterZ = Expression.Parameter(typeof(int), "z");
Expression multiplyYZ = Expression.Multiply(parameterY, parameterZ);
Expression addXMultiplyYZ = Expression.Add(parameterX, multiplyYZ);
Func<int,int,int,int> f = Expression.Lambda<Func<int, int, int, int>>
(
    addXMultiplyYZ,
    parameterX,
    parameterY,
    parameterZ
).Compile();
Console.WriteLine(f(24, 6, 3)); // prints 42 to the console
Sign up to request clarification or add additional context in comments.

2 Comments

+1 This is a good example but is tailored to the string in question. This example wouldn't help the OP parse a random string, infer the types of the identifiers in the string, and create a method based on what was found. Nevertheless, +1 to you for the good example.
I assumed that parsing would be more familiar (at least the literature on parsing is larger) to the OP than expression trees. The purpose of the expression tree is solely to show the technology to him and to show their power, not to solve the general problem.
8

Just for fun using CodeDom (any valid C# code is allowed in the string as long as it is present in mscorlib (No check for errors at all):

static class Program
{
    static string code = @"
        public static class __CompiledExpr__
        {{
            public static {0} Run({1})
            {{
                return {2};
            }}
        }}
        ";

    static MethodInfo ToMethod(string expr, Type[] argTypes, string[] argNames, Type resultType)
    {
        StringBuilder argString = new StringBuilder();
        for (int i = 0; i < argTypes.Length; i++)
        {
            if (i != 0) argString.Append(", ");
            argString.AppendFormat("{0} {1}", argTypes[i].FullName, argNames[i]);
        }
        string finalCode = string.Format(code, resultType != null ? resultType.FullName : "void",
            argString, expr);

        var parameters = new CompilerParameters();
        parameters.ReferencedAssemblies.Add("mscorlib.dll");
        parameters.ReferencedAssemblies.Add(Path.GetFileName(Assembly.GetExecutingAssembly().Location));
        parameters.GenerateInMemory = true;

        var c = new CSharpCodeProvider();
        CompilerResults results = c.CompileAssemblyFromSource(parameters, finalCode);
        var asm = results.CompiledAssembly;
        var compiledType = asm.GetType("__CompiledExpr__");
        return compiledType.GetMethod("Run");
    }

    static Action ToAction(this string expr)
    {
        var method = ToMethod(expr, new Type[0], new string[0], null);
        return () => method.Invoke(null, new object[0]);
    }

    static Func<TResult> ToFunc<TResult>(this string expr)
    {
        var method = ToMethod(expr, new Type[0], new string[0], typeof(TResult));
        return () => (TResult)method.Invoke(null, new object[0]);
    }

    static Func<T, TResult> ToFunc<T, TResult>(this string expr, string arg1Name)
    {
        var method = ToMethod(expr, new Type[] { typeof(T) }, new string[] { arg1Name }, typeof(TResult));
        return (T arg1) => (TResult)method.Invoke(null, new object[] { arg1 });
    }

    static Func<T1, T2, TResult> ToFunc<T1, T2, TResult>(this string expr, string arg1Name, string arg2Name)
    {
        var method = ToMethod(expr, new Type[] { typeof(T1), typeof(T2) },
            new string[] { arg1Name, arg2Name }, typeof(TResult));
        return (T1 arg1, T2 arg2) => (TResult)method.Invoke(null, new object[] { arg1, arg2 });
    }

    static Func<T1, T2, T3, TResult> ToFunc<T1, T2, T3, TResult>(this string expr, string arg1Name, string arg2Name, string arg3Name)
    {
        var method = ToMethod(expr, new Type[] { typeof(T1), typeof(T2), typeof(T3) },
            new string[] { arg1Name, arg2Name, arg3Name }, typeof(TResult));
        return (T1 arg1, T2 arg2, T3 arg3) => (TResult)method.Invoke(null, new object[] { arg1, arg2, arg3 });
    }

    static void Main(string[] args)
    {
        var f = "x + y * z".ToFunc<int, int, long, long>("x", "y", "z");
        var x = f(3, 6, 8);

    }
}

Comments

5

C# doesn't have any functionality like this (other languages - like JavaScript - have eval functions to handle stuff like this). You will need to parse the string and create a method yourself with either expression trees or by emitting IL.

Comments

2

There are functionality to do this in the .Net framework.

It is not easy. You need to add some code around the statement to make it into a complete assembly including a class and method you can call.

After that you pass the string to

CSharpCodeProvider.CompileAssemblyFromSource(options, yourcode);

Here is an example

1 Comment

Along with figuring out what parameters are required, etc. Tough to make friendly with CompileAssemblyFromSource.
1

It could be possible with a grammar (e.g. ANTLR) and an interpreter which creates expression trees. This is no small task, however, you can be successful if you limit the scope of what you accept as input. Here are some references:

Here is what some code may look like to transform an ANTLR ITree into an Expression tree. It isn't complete, but shows you what you're up against.

private Dictionary<string, ParameterExpression> variables
    = new Dictionary<string, ParameterExpression>();

public Expression Visit(ITree tree)
{
    switch(tree.Type)
    {
        case MyParser.NUMBER_LITERAL:
            {
                float value;
                var literal = tree.GetChild(0).Text;
                if (!Single.TryParse(literal, out value))
                    throw new MyParserException("Invalid number literal");
                return Expression.Constant(value);
            }

        case MyParser.IDENTIFIER:
            {
                var ident = tree.GetChild(0).Text;
                if (!this.variables.ContainsKey(ident))
                {
                    this.variables.Add(ident,
                       Expression.Parameter(typeof(float), ident));
                }

                return this.variables[ident];
            }

        case MyParser.ADD_EXPR:
            return Expression.Add(Visit(tree.GetChild(0)), Visit(tree.GetChild(1)));

        // ... more here
    }
}

Comments

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.