Как вставить лямбду в выражение декларативного запроса Linq - PullRequest
5 голосов
/ 19 октября 2010

Допустим, у вас есть следующий код:

  string encoded="9,8,5,4,9";

  // Parse the encoded string into a collection of numbers
  var nums=from string s in encoded.Split(',')
           select int.Parse(s);

Это просто, но что, если я хочу применить лямбда-выражение к s в select, но все равно оставить это как декларативное выражение запроса, вДругими словами:

  string encoded="9,8,5,4,9";

  // Parse the encoded string into a collection of numbers
  var nums=from string s in encoded.Split(',')
           select (s => {/* do something more complex with s and return an int */});

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

Обновление : Благодаря руководству StriplingWarrior у меня есть замысловатое, но компилируемое решение:

var result=from string s in test.Split(',')
           select ((Func<int>) 
             (() => {string u="1"+s+"2"; return int.Parse(u);}))();

Ключ находится в приведении к Func<string,int> с последующей оценкой лямбда-выражения для каждой итерации выбора с помощью (s).Может ли кто-нибудь придумать что-нибудь попроще (т. Е. Без приведения к Func с последующей его оценкой или, возможно, чего-то менее многословного, которое достигает того же конечного результата при сохранении синтаксиса выражения запроса)?

Примечание. Содержимое лямбды, приведенное выше, является тривиальным и примерным по своей природе.Пожалуйста, не меняйте его.

Обновление 2 : Да, это я, сумасшедший Майк, вернулся с альтернативным (более симпатичным?) Решением этого вопроса:

public static class Lambda
{
  public static U Wrap<U>(Func<U> f)
  {
    return f();
  }
}
... 
  // Then in some function, in some class, in a galaxy far far away:

  // Look what we can do with no casts
  var res=from string s in test.Split(',')
          select Lambda.Wrap(() => {string u="1"+s+"2"; return int.Parse(u);});

Я думаю, что это решает проблему без уродливого броска и паренореи.Что-то вроде универсального метода Lambda.Wrap уже присутствует где-то в .NET 4.0 Framework, так что мне не нужно изобретать велосипед?Чтобы не перегружать это обсуждение, я перенес этот вопрос в отдельный вопрос: Существует ли этот универсальный метод "Wrap" в .NET 4.0 .

Ответы [ 5 ]

2 голосов
/ 19 октября 2010

Если вы используете LINQ to Objects, вы можете просто использовать вспомогательный метод:

select DoSomethingComplex(s)

Если вам не нравятся методы, вы можете использовать Func:

Func<string, string> f = s => { Console.WriteLine(s); return s; };
var q = from string s in new[]{"1","2"}
        select f(s);

Или, если вы полностью одержимы этим, вы можете сделать что-то вроде этого:

from string s in new[]{"1","2"}
select ((Func<string>)(() => { Console.WriteLine(s); return s; }))()
0 голосов
/ 19 октября 2010

IEnumerable integer = encoded.Split (','). Select (s => int.Parse (s));

Редактировать:

IEnumerable<int> integers = from s in encoded.Split(',') select int.Parse(string.Format("1{0}2",s));
0 голосов
/ 19 октября 2010

Может кто-нибудь придумать что-нибудь проще?

Да. Во-первых, вы могли бы переписать это так

var result = from s in encoded.Split(',')
             select ((Func<int>)(() => int.Parse("1" + s + "2")))();

Однако, это не совсем читабельно, особенно для выражения запроса. Для этого конкретного запроса и проекции можно использовать ключевое слово let.

var result = from s in encoded.Split(',')
             let t = "1" + s + "2"
             select int.Parse(t);
0 голосов
/ 19 октября 2010

Как насчет этого:

var nums= (from string s in encoded.Split(',') select s).Select( W => ...);
0 голосов
/ 19 октября 2010

Вы могли бы просто сделать:

var nums = from string s in encoded.Split(',')
           select (s => { DoSomething(); return aValueBasedOnS; });

Возвращение сообщает компилятору тип полученной коллекции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...