开发者

How to insert a lambda into a Linq declarative query expression

Let's say you have the following code:

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

That's easy, but what if I want to apply a lambda expression to s in the select, but still 开发者_如何学运维keep this as a declarative query expression, in other words:

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

This of course does not compile. But, how can I get a lambda in there without switching this to fluent syntax.

Update: Thanks to guidance from StriplingWarrior, I have a convoluted but compilable solution:

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

The key is in the cast to a Func<string,int> followed by evaluation of the lambda for each iteration of the select with (s). Can anyone come up with anything simpler (i.e., without the cast to Func followed by its evaluation or perhaps something less verbose that achieves the same end result while maintaining the query expression syntax)?

Note: The lambda content above is trivial and exemplary in nature. Please don't change it.

Update 2: Yes, it's me, crazy Mike, back with an alternate (prettier?) solution to this:

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

I think this solves the problem without the ugly cast and parenarrhea. Is something like the Lambda.Wrap generic method already present somewhere in the .NET 4.0 Framework, so that I do not have to reinvent the wheel? Not to overburden this discussion, I have moved this point into its own question: Does this "Wrap" generic method exist in .NET 4.0.


Assuming you're using LINQ to Objects, you could just use a helper method:

select DoSomethingComplex(s)

If you don't like methods, you could use a Func:

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

Or if you're completely hell-bent on putting it inline, you could do something like this:

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


You could simply do:

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

The return tells the compiler the type of the resulting collection.


How about this:

var nums= (from string s in encoded.Split(',') select s).Select( W => ...);


Can anyone come up with anything simpler?

Yes. First, you could rewrite it like this

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

However, that's not really readable, particularly for a query expression. For this particular query and projection, the let keyword could be used.

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


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

Edit:

IEnumerable<int> integers = from s in encoded.Split(',') select int.Parse(string.Format("1{0}2",s));
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜