Created
December 5, 2013 13:10
-
-
Save controlflow/7804901 to your computer and use it in GitHub Desktop.
How C# lambdas with a single ref-type immutable closure can be optimized
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
static class LiftingClosureToDelegateTarget { | |
static void Main() { | |
// normal lambda | |
{ | |
var str = GetString(); | |
Func<string> f = () => str; | |
Console.WriteLine(f()); | |
} | |
// what is generated (two allocations: closure and delegate) | |
{ | |
var closure = new Closure(); | |
closure._str = GetString(); | |
Func<string> f = new Func<string>(closure.LambdaBody); | |
Console.WriteLine(f()); | |
} | |
// what CAN be generated if captured variable is immutable (single allocation: delegate) | |
// delegate instance contains both 'str' reference and a function pointer to static method | |
{ | |
var str = GetString(); | |
Func<string> f = new Func<string>(str.LambdaBodyAsExtensionMethod); | |
Console.WriteLine(f()); | |
} | |
// the same with reflection | |
{ | |
var str = GetString(); | |
Func<string> f = (Func<string>) Delegate.CreateDelegate( | |
type: typeof (Func<string>), | |
firstArgument: str, // <-- all magic is here | |
method: typeof (LiftingClosureToDelegateTarget).GetMethod("LambdaBodyAsExtensionMethod")); | |
Console.WriteLine(f()); | |
} | |
} | |
private static string GetString() { | |
return "abc"; | |
} | |
private sealed class Closure { | |
public string _str; | |
public string LambdaBody() { return _str; } | |
} | |
public static string LambdaBodyAsExtensionMethod(this string str) { | |
return str; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment