Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Expression tree for String.IndexOf method

How should I construct Expression tree for string.IndexOf("substring", StringComparison.OrdinalIgnoreCase)?

I can get it working without the second argument: StringComparison.OrdinalIgnoreCase. These are my attempts so far:

var methodCall = typeof (string).GetMethod("IndexOf", new[] {typeof (string)});
Expression[] parms = new Expression[]{right, Expression.Constant("StringComparison.OrdinalIgnoreCase", typeof (Enum))};
var exp =  Expression.Call(left, methodCall, parms);
return exp;

Also tried this:

var methodCall = typeof (string).GetMethod(method, new[] {typeof (string)});
Expression[] parms = new Expression[]{right, Expression.Parameter(typeof(Enum) , "StringComparison.OrdinalIgnoreCase")};
var exp =  Expression.Call(left, methodCall, parms);
return exp;

Please remember that I can get it working if I ignore the OrdinalIgnoreCase parameter.

Thanks

like image 784
ashokgelal Avatar asked Aug 17 '11 07:08

ashokgelal


People also ask

How do I find indexOf strings?

The indexOf() method returns the position of the first occurrence of specified character(s) in a string. Tip: Use the lastIndexOf method to return the position of the last occurrence of specified character(s) in a string.

What is expression tree in Linq?

Expression trees represent code in a tree-like data structure, where each node is an expression, for example, a method call or a binary operation such as x < y . You can compile and run code represented by expression trees.

How many indexOf methods does the string have?

There are four variants of indexOf() method.

What is Expression C#?

An expression in C# is a combination of operands (variables, literals, method calls) and operators that can be evaluated to a single value. To be precise, an expression must have at least one operand but may not have any operator.


2 Answers

I suspect there are two problems.

The first is the way you're getting the method - you're asking for a method with only a single string parameter, instead of one with two parameters:

var methodCall = typeof (string).GetMethod("IndexOf",
                            new[] { typeof (string), typeof(StringComparison) });

The second is the value you're giving - it should be the actual value of the constant, not a string:

Expression[] parms = new Expression[] { right, 
    Expression.Constant(StringComparison.OrdinalIgnoreCase) };

EDIT: Here's a complete working sample:

using System;
using System.Linq.Expressions;

class Test
{
    static void Main()
    {
        var method = typeof (string).GetMethod("IndexOf",
                new[] { typeof (string), typeof(StringComparison) });

        var left = Expression.Parameter(typeof(string), "left");
        var right = Expression.Parameter(typeof(string), "right");

        Expression[] parms = new Expression[] { right, 
                Expression.Constant(StringComparison.OrdinalIgnoreCase) };

        var call = Expression.Call(left, method, parms);
        var lambda = Expression.Lambda<Func<string, string, int>>
            (call, left, right);

        var compiled = lambda.Compile();
        Console.WriteLine(compiled.Invoke("hello THERE", "lo t"));
    }
}
like image 182
Jon Skeet Avatar answered Nov 07 '22 19:11

Jon Skeet


The simplest way to do it would be to get it via a lambda like this:

//the compiler will convert the lambda into an expression
Expression<Func<string, string, int>> expression = (s1, s2) => s1.IndexOf(s2, StringComparison.OrdinalIgnoreCase);
//compile the expression so we can call it
var func = expression.Compile();
//outputs 2
Console.WriteLine(func("Case Sensitive", "se sensitive"));

This is much more readable and maintainable than manually building an expression tree.

I'm constantly surprised by the amount of people who dive straight into manually building expression trees. There's no need to when you can get the compiler to do the work for you.

like image 40
Doctor Jones Avatar answered Nov 07 '22 20:11

Doctor Jones