views:

147

answers:

4

Does the following generic function exist anywhere in the .NET 4.0 framework? I would like to reuse it if it does rather than writing it myself:

public static class Lambda 
{ 
  public static U Wrap<U>(Func<U> f) 
  { 
    return f(); 
  } 
} 

It allows for the following construct (i.e., lambda expressions embedded in the select clause of a LINQ query):

string test="12,23,34,23,12";
var res=from string s in test.Split(',') 
        select Lambda.Wrap(() => {string u=s+s; return int.Parse(u);});

Update: To all people questioning this solution, look at Onkelborg's answer to see what it would take to include the lambda without Lambda.Wrap() (while still maintaining query syntax). Please do not eliminate the lambda. This has to work for abitrary (value returning) lambdas. Also, I am looking for a query syntax solution, only. Please do not convert the expression to fluent syntax, thus trivializing it.

+1  A: 

According to Reflector, that method doesn't exist. But I don't see why you would need it :)

string test = "12,23,34,23,12";
var res = from string s in test.Split(',')
          select ((Func<int>)(() => { string u = s + s; return int.Parse(u); }))();

I think this would be exactly the same thing

Onkelborg
Did you try compiling that without an explict cast to Func<int> ?
Michael Goldshteyn
No, I haven't tried compiling anything. But since your delegate return an int I see no reason
Onkelborg
+1 for checking with reflector and for producing a shorter solution.
Shiftbit
Well, I should vote this -1 because this does not compile and is invalid C# code, but I won't since I am the question author.
Michael Goldshteyn
Hm, why doesn't it compile? Maybe, you might need to do (() => {string u=s+s; return int.Parse(u);}).Invoke() instead. Will test now
Onkelborg
Nope, that won't work, either.
Michael Goldshteyn
Ok, LINQ seems to be picky. Updating answer with a cast
Onkelborg
+1  A: 

How is this different from

var res = test.Split(',').Select(s => {
                                        var u = s + s;
                                        return int.Parse(u);
                                      });

?

Yes, this compiles and runs.

Jarrett Meyer
It's different, because as the question said, I want to preserve query syntax (not use fluent syntax) to solve this problem.
Michael Goldshteyn
+6  A: 

You can use the let syntax in your code:

string test = "12,23,34,23,12";
var res = from string s in test.Split(',') 
          let u = s+s
          select int.Parse(u);

Alternately, you could use the LINQ extension methods directly instead of the special syntax:

string test = "12,23,34,23,12";
var res = test.Split(',')
              .Select(s => { var u = s + s; return int.Parse(u); });

Since the question was updated:

I don't mean to be disrespectful, but I think this solution isn't necessary.

Here's a bit of an exploration:

If we want to accept truly "arbitrary" lambdas like you say, then they can come from an outside source, and Wrap does nothing because it's the same as f():

// with 'f' as some arbitrary lambda, then this:
var res = from string s in test.Split(',')
          select f.Wrap();

// is the same as:
var res = from string s in test.Split(',')
          select f();

But if you do this, f can't depend upon s in any way (for example, this way you can't write your example code):

// e.g. where does s come from?
var f = () => { var u = s+s; return int.Parse(u); }; 

// we can write it like this, as a function of 's':
var f2 = s => { var u = s+s; return int.Parse(u); };
//but then you can just use "select f2(s)" and we're back not needing Wrap any more

What we're really looking for is arbitrary closures over s. For this to happen, the lambdas have to be defined inline, where s is in scope, so you aren't really accepting truly "arbitrary" lambdas any more, and they have to be written directly in the code.

This is why I proposed the let syntax, since any lambda you can come up with can be converted to that syntax, and it goes with the rest of the query syntax. This is what let is designed for! :)

Alternately, you could just use lambdas which take parameters like f2 above.

If you really want to stick with the lambda syntax, I'd suggest using the extension methods. Like I said in my comment, it looks like you're looking for something halfway between query & extension syntax.

I'd be interested in why you want to use the lambda syntax with the query syntax?

Hope this helps :)

Porges
How does the former allow the use of arbitrary lambda expressions? How does the later preserve query syntax?
Michael Goldshteyn
Well I think the reason you have the problem in the first place is that you want something halfway between query syntax and the extension method syntax :) Query syntax doesn't "think" in terms of lambdas, but extension syntax does. I have more to explain so I'll update my comment.
Porges
Let me start by answering this question: I'd be interested in why you want to use the lambda syntax with the query syntax? The reason is that, as has been mentioned many times on SO, query syntax has its advantages in certain cases. When one of those cases appears and one would like to use an arbitrary lambda as part of that case, it would be nice to be able to insert it into the query, without falling back to fluent syntax (because the lambda cannot be inserted, without sloppy casts, etc...).
Michael Goldshteyn
In answer to your issues with f() depending on s, there really is no issue for what I am trying to solve. Lambda.Wrap is just a place holder that "beautifies" Onkelborg's solution (involving ugly syntax with casts and a function call.) The terms coming from the "from" part(s) of the query can still be used in the lambda expression itself, because it is part of the query. Yes, there may be issues with lambdas from an outside source, but that is outside the scope of my discussion of simple embedded lambdas that work with the variables coming from the "from" expression(s).
Michael Goldshteyn
Now, given the above comments, maybe a remark can be made that there is no need for such trivial lambdas at all (i.e., they can be eliminated), but surely there are flaws with this statement, even if I can't think of a good lambda that must remain a (from variable dependant lambda) and is not easily eliminated and replaced with a let subexpression. Feel free to prove me wrong on this point.
Michael Goldshteyn
It needs not be said that you are bringing up some interesting and valid points, so let's continue the discussion further and I've upvoted your solution in the mean time.
Michael Goldshteyn
By the way, f2 cannot be defined with var syntax, it must be: Func<string,int> f2 = s => { var u = s + s; return int.Parse(u); }; // At which point select f2(s) does work, making Wrap unnecessary. But, this is for an external (not to mention explicitly typed) lambda.
Michael Goldshteyn
Yes, I left f2 just like that. It's not meant to be runnable :) I would assume it would come in as a method parameter, in which case the parameter would be typed (and a non-explicitly typed lambda can be passed in that parameter position).
Porges
To follow up on: "even if I can't think of a good lambda that must remain a (from variable dependant lambda) and is not easily eliminated and replaced with a let subexpression". I must say that at the moment I would take the position that this *is* the case, and that one should write them with `let`. :)
Porges
OK, I'll let this simmer for another day or two. If no other ideas come in (as answers), you win (the checkmark).
Michael Goldshteyn
A: 

No, it does not exist. Onkelborg's solution is the best you can do out of the box, so if you do really want to execute an arbitrary code block inside a LINQ expression, then I would author the Wrap function you suggest in order to get C# type inference to kick in and make it less ugly.

Brian