I am writing a component that involves Actions and came upon a requirement to find a way to identify using reflection cases when the Action.Target object is a closure that the compiler have generated. I am doing an experiment to try and find a way, the purpose of this little experiment is to develop a predicate that takes an Action and returns a bool that tells if the action target is an instance of such closure class.
In my test case, I have the following methods that create 4 different types of actions:
private void _createClosure(int i)
{
ClosureAction = new Action(() =>
{
var j = i;
var k = somenum;
});
}
private void _createLambda()
{
LambdaAction = new Action(() =>
{
this._instanceAction();
});
}
private void _createInstance()
{
InstanceAction = new Action(_instanceAction);
}
private void _createStatic()
{
StaticAction = new Action(_staticAction);
}
private int somenum;
private void _instanceAction()
{
somenum++;
}
private static void _staticAction()
{
}
The following table shows the properties of each action:
As you see, LambaAction and ClosureAction are quite similar in terms of defnition, they both use lambda, but the closure one has a local function variable that is being used inside the lambda, and therefore the compiler is forced into generating a closure class. Its clear that the second row, the one that presents ClosureAction, is the only one that has a target that is a closure type. The static one does not have a target at all, and the other two use the calling class (Called ActionReferences) as target. The next table presents a comparison of the target reflection type properties:
So we can see that what's unique about the closure case is that the target type is not a type info but rather a nested type. It's also the only one that is private nested, sealed and has a name that contains the string +<>c__DisplayClass. Now while I think that these characteristics are conclusive for any normal usage case, I would prefer to define a predicate that I can rely on. I don't like to base this mechanism on compilers naming conventions or properties that are not unique because technically, the user may create a private nested sealed class with the same naming convention... it's not likely, but it's not 100% clean solution.
So finally - the question is this: Is there a clean cut way to write a predicate the identifies actions that are actually compiler generated closures?
Thanks
A lambda expression is an anonymous function and can be defined as a parameter. The Closures are like code fragments or code blocks that can be used without being a method or a class. It means that Closures can access variables not defined in its parameter list and also assign it to a variable.
a function that can be treated as an object is just a delegate. What makes a lambda a closure is that it captures its outer variables. lambda expressions converted to expression trees also have closure semantics, interestingly enough.
This isn't 100% accurate, but it generally works:
bool isClosure = action.Target != null && Attribute.IsDefined(
action.Target.GetType(), typeof(CompilerGeneratedAttribute));
Console.WriteLine(isClosure);
You can of course force false positives just by manually adding [CompilerGenerated]
to any type you choose.
You could also use action.Method.DeclaringType
, but since all captures involve a target instance, it is useful to retain the Target
check:
bool isClosure = action.Target != null && Attribute.IsDefined(
action.Method.DeclaringType, typeof(CompilerGeneratedAttribute));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With