Перевод лямбда-выражения в дерево выражений - PullRequest
0 голосов
/ 28 сентября 2011

Реальная проблема, которую я пытаюсь решить: у меня есть база данных с кучей телефонных номеров, которые хранятся в виде строк в абсолютно ужасном формате (например, "(02) 9971 1209"). Пользователь моей программы начнет набирать телефонный номер, и по мере того, как он печатает, то, что он печатает, будет отсылаться и использоваться для фильтрации списка телефонных номеров в базе данных с помощью операции «старт с».

Проблема в том, что если пользователь введет «02997», он не будет ничего совпадать, потому что числа хранятся с кодом местоположения, заключенным в скобки. Чтобы эта операция работала, пользователь должен будет начать каждый поиск, набрав '('. Это не хорошо.

tl; dr версия внизу вопроса

Я вынул проблему из контекста реального мира и превратился в меньшее, запечатанное решение, где я могу сосредоточиться на ней, не отвлекаясь от массивной кодовой базы. В таких условиях моим решением было сделать несколько хитростей:

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

Это все хорошо, отлично работает, делает именно то, что мне нужно. Но это работает только в этом изолированном контексте: я не могу перенести его обратно в кодовую базу, где он должен быть реализован, потому что мне нужно перевести его в дерево выражений.

Код, где мне нужно разбить его:

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

Мне нужно взять 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)));

Я хотел сделать что-то подобное, но это не решает проблему, но немного аккуратнее:

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

Я пытался применить к нему множество небольших изменений, но он отказывается компилироваться.

ТЛ; др:

Короче говоря, мне нужно взять выражение, представляющее поле таблицы в базе данных, и преобразовать это выражение в выражение, представляющее ту же вещь, но с примененным фильтром, который удаляет все символы, которые не являются цифры.

1 Ответ

5 голосов
/ 28 сентября 2011

Многие выражения, которые вы хотели бы использовать для получения сокращенной версии телефонных номеров, вероятно, не будут поддерживаться вашим поставщиком LINQ.

Я бы лично предложил создать базу данных.показывает все номера телефонов в их урезанном формате.Затем вы можете просто выполнить стандартный запрос StartsWith для этого представления.

...