7

As of C# 6, lambdas now default to instance methods, and will never be static (which I assume means they always capture now, which I guess is more efficient [seems to be faster given the discussions]).

See here: Why has a lambda with no capture changed from a static in C# 5 to an instance method in C# 6?

and here: Difference in CSC and Roslyn compiler's static lambda expression evaluation?

This causes issues now with using lambdas when creating static MethodInfos for calls to expression methods such as Expression.Convert(Expression, typeof({SomeType}), conversionMethodInfo);

So then, what is the new way of doing this? I tried to use the "static" modifier with lambdas and it doesn't work. For those who can't imagine such code, this might be one example:

Func <T1,T2> converter = static v => ConvertT1ToT2(v); // ('T' is whatever type you want)
Expression.Convert(expression, typeof({SomeType}), converter.Method) // (error: converter.Method.IsStatic is false)

Yes, obviously it doesn't work.

Community
  • 1
  • 1
James Wilkins
  • 6,836
  • 3
  • 48
  • 73
  • Can you show us what you “tried” and why you think “it doesn't work”? – Dour High Arch Apr 04 '17 at 21:30
  • 1
    How can anyone try anything when the spec changed and now there's no docs on the new thing? lol Picture a lambda expression, then imagine all the ways to put "static" modifier on it, that's what I tried (which I knew wasn't possible, but just in case they were smart enough to put it in this release to compensate). – James Wilkins Apr 04 '17 at 22:06
  • Is there a reason you couldn't promote it to a private static expression-valued member? – Dai Apr 04 '17 at 22:25
  • 1
    Yes, because it doesn't solve the issue. ;) (nor answer the question) – James Wilkins Apr 04 '17 at 22:32
  • 1
    For that matter why stop there? Just promote it to an actual static method and litter my class with them. ;) I was hoping to keep them grouped in the one and only method it is used in, but now I may have to "dirty" my class. – James Wilkins Apr 04 '17 at 22:43
  • Related: http://stackoverflow.com/a/33948251/533837 – AnorZaken May 09 '17 at 14:45

2 Answers2

6

So then, what is the new way of doing this?

There isn't one. The spec never promised anything about the implementation details of lambda expressions. Which is why you should not depend on them. It's also why What's new in C# 6 does not mention this.

Assuming you need to use Expression.Convert with a custom MethodInfo, then you should promote the lambda into a static method:

private static T2 Converter(T1 v)
{
    return ConvertT1ToT2(v);
}

…

MethodInfo converter =
    typeof(ThisType).GetMethod("Converter", BindingFlags.NonPublic | BindingFlags.Static);
// OR:
MethodInfo converter = ((Func<T1, T2>)Converter).Method;

Expression.Convert(expression, typeof(SomeType), converter)

This way, you're not using a lambda, so it's guaranteed the MethodInfo refers to a static method.

svick
  • 236,525
  • 50
  • 385
  • 514
0

In case others wish to know, in the end, I had to promote (demote? lol) my expressions to "Expression-bodied function members" instead, like this:

// (class method)
static string _Convert(object obj) => (obj as SomeType)?.SomeProperty ?? ReturnSomethingElse;

then in my method body:

Func<object, string> conversionDelegate = _Convert;
Expression exp = Expression.Convert(expression, typeof(SomeType), conversionDelegate.Method);

Edit: Some talk about non-capturing/static lambdas here: https://github.com/dotnet/csharplang/issues/275

James Wilkins
  • 6,836
  • 3
  • 48
  • 73
  • 1
    I don't think it's a smart decision to force people to end up cluttering their classes with private static expressions, but we can only hope one day the "static" modifier can work on lambdas as well. While one thing might be a bit more efficient, another becomes more annoying. It's like one step forward and another back, but oh well. – James Wilkins Apr 05 '17 at 17:12
  • LOL, downvote the solution that works for me, and without explanation, ok. – James Wilkins Apr 05 '17 at 17:15