将lambda表达式转换为表达式树

The*_*kle 0 .net c# linq expression-trees

我正在尝试解决的现实世界问题:我有一个数据库,其中一堆电话号码以绝对可怕的格式存储为字符串(例如"(02)9971 1209").我的程序的用户将开始输入电话号码,当他输入时,他将输入的内容将被发送并用于使用"startswith"操作过滤数据库中的电话号码列表.

问题是,如果用户键入"02997",它将不会匹配任何内容,因为数字与位于括号中的位置代码一起存储.为了使此操作起作用,用户必须通过键入'(')来开始每次搜索.这不好.

tl;问题底部的博士版本

我把这个问题从它的真实世界环境中解决出来,变成了一个更小,更密集的解决方案,我可以专注于它而不会分散大量的代码库.在这种情况下,我的解决方案是做一些linq棘手:

class Program
{
    static string [] phones = {"(02) 9489 3048","(04) 1128 2148","(01) 9971 1208",};

    static void Main(string[] args)
    {
        for (;;)
        {
            Console.WriteLine("Enter your number: ");
            string input = Console.ReadLine();

            Func<string, string> strip = 
            tehstring => tehstring.Where(x => char.IsDigit(x))
                                  .Aggregate("", (x, y) => x + y);
            var results = phones.Where(z => strip(z).StartsWith(strip(input)));

            foreach (var x in results)
                Console.WriteLine(x);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这一切都很好,效果很好,完全符合我的需要.但它只适用于这个孤立的上下文:我无法将其移回需要实现的代码库,因为我需要将其转换为表达式树.

我需要解决的代码:

static Expression GetOperationExpression(
  StringFilterOperation operation, 
  Expression propertyExpression, 
  Expression valueExpression)
{
  switch (operation)
  {
    case StringFilterOperation.StartsWith:
    var startsWith = typeof(string)
                     .GetMethod("StartsWith", new Type[] { typeof(string) });
    Contract.Assume(startsWith != null);
    return Expression.Call(propertyExpression, startsWith, valueExpression);
    //etc etc etc
Run Code Online (Sandbox Code Playgroud)

我需要使用propertyExpression,并以某种方式在我的lambda函数中嵌入它正在讨论的属性(在这种情况下是外部数据库中的电话号码表).然后我需要将整个事物反编译回表达式树并返回它.

那就是我被困住的地方.我能想到的最好的是超长且不优雅的linq系列,它甚至都没有正确的类型:

Expression<Func<string[],string, IEnumerable<string>>> expr = 
(db, uinput) => db.Where(z => z.Where(x => char.IsDigit(x))
                               .Aggregate("", (x, y) => x + y)
                               .StartsWith(uinput.Where(x => char.IsDigit(x))
                                                 .Aggregate("",(x,y) => x + y)));
Run Code Online (Sandbox Code Playgroud)

我想做这样的事情,但仍然没有解决问题但是有点整洁:

Expression<Func<string, string>> strip = 
tehstring => tehstring.Where(x => char.IsDigit(x))
                      .Aggregate("", (x, y) => x + y);
Expression<Func<string, string, string>> query = 
(db, uinput) => db.Where(z => strip(z)
                  .StartsWith(strip(uinput)));
Run Code Online (Sandbox Code Playgroud)

我尝试过对它进行大量的改动,但它拒绝编译.

TL;博士:

简而言之,我需要做的是在数据库中的表上使用表示字段的表达式,并将该表达式转换为表示相同内容的表达式,但应用了一个过滤器,用于删除非数字的所有字符.

Str*_*ior 5

您的LINQ提供程序可能不支持您希望用于获取电话号码的剥离版本的许多表达式.

我个人建议制作一个数据库视图,以其精简格式显示所有电话号码.然后,您可以StartsWith对该视图执行标准查询.