【问题标题】:Expression tree for String.IndexOf methodString.IndexOf 方法的表达式树
【发布时间】:2011-08-17 07:27:08
【问题描述】:

我应该如何为string.IndexOf("substring", StringComparison.OrdinalIgnoreCase)构造表达式树?

没有第二个参数我可以让它工作:StringComparison.OrdinalIgnoreCase。这些是我迄今为止的尝试:

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;

也试过这个:

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;

请记住,如果我忽略 OrdinalIgnoreCase 参数,我可以让它工作。

谢谢

【问题讨论】:

  • 与以往一样,当您遇到问题时,您应该说出您尝试过的问题 - 您是否遇到异常、编译时错误或错误行为?如果是某种错误,那是什么错误?
  • 对不起。下次提问时我会记住这一点。我得到了一个 ArgumentException。

标签: c# reflection expression-trees linq-expressions


【解决方案1】:

我怀疑有两个问题。

第一个是你获取方法的方式——你要求一个只有一个字符串参数的方法,而不是一个有两个参数的方法:

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

第二个是您提供的 - 它应该是常量的实际值,而不是字符串:

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

编辑:这是一个完整的工作示例:

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"));
    }
}

【讨论】:

  • 有没有办法对contains 方法做同样的事情?
  • @atp9:是的。您尝试了什么,出了什么问题?
  • 我试过这样的:MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string),typeof(StringComparison) }); var expressionbody = System.Linq.Expressions.Expression.Call(prop, method, new [] { valuetocompare, System.Linq.Expressions.Expression.Constant(StringComparison.OrdinalIgnoreCase) }); 但是这个给我一个错误
  • @atp9:鉴于 cmets 对扩展代码段并不是很好,我建议您使用 minimal reproducible example 提出一个新问题。
【解决方案2】:

最简单的方法是通过这样的 lambda 获取它:

//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"));

这比手动构建表达式树更具可读性和可维护性。

我一直对直接投入手动构建表达式树的人数感到惊讶。不需要什么时候可以让编译器为您完成工作。

【讨论】:

  • +1,当编译器可以为您完成时,没有理由手动构建表达式树
  • @Thomas: 是的,但我们看不到leftright 的来源……他们大概是Expression 类型,而不是string
  • 可能这是更好的方法,但我正在处理的库 (github.com/ashokgelal/NetFilterFramework) 是通过手动构建表达式树来构建的。现在我只需要添加一个字符串比较方法调用,但可能我需要使用 lambdas 重构/重写所有内容。
【解决方案3】:

我没有检查它的其余部分,但如果只有枚举会造成问题:

Expression.Constant(StringComparison.OrdinalIgnoreCase)

Expression.Constant(Enum.Parse(typeof(StringComparison), "OrdinalIgnoreCase"), typeof(Enum));

而且您还有更多选择。或者查看我的回答here

编辑:忘记括号了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多