我正在编写一个涉及Actions的组件,当Action.Target对象是编译器生成的闭包时,需要找到一种方法来识别使用反射的情况。我正在做一个尝试找到方法的实验,这个小实验的目的是开发一个谓词,它接受一个Action并返回一个bool,告诉动作目标是否是这种闭包类的一个实例。
在我的测试用例中,我有以下方法可以创建4种不同类型的操作:
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()
{
}
下表显示了每个操作的属性:
如你所见,LambaAction和ClosureAction在定义方面非常相似,它们都使用lambda,但是闭包有一个在lambda中使用的本地函数变量,因此编译器被强制生成一个闭包类。很明显,第二行,即呈现ClosureAction的那一行,是唯一一个具有闭包类型的目标。静态的根本没有目标,另外两个使用调用类(Called ActionReferences)作为目标。下表显示了目标反射类型属性的比较:
因此,我们可以看到关闭案例的独特之处在于目标类型不是类型信息,而是嵌套类型。它也是唯一一个私有嵌套,密封并且名称包含字符串+<> c__DisplayClass的人。虽然我认为这些特性对于任何正常的用例都是决定性的,但我更愿意定义一个我可以依赖的谓词。我不想将此机制建立在编译器命名约定或属性上,这些机制不是唯一的,因为从技术上讲,用户可能会创建一个具有相同命名约定的私有嵌套密封类......它不太可能,但是它不是100%清洁的解决方案。
最后 - 问题是:是否有一种简洁的方法来编写谓词,识别实际上是编译器生成的闭包的动作?
由于
答案 0 :(得分:3)
这不是100%准确,但通常有效:
bool isClosure = action.Target != null && Attribute.IsDefined(
action.Target.GetType(), typeof(CompilerGeneratedAttribute));
Console.WriteLine(isClosure);
您当然可以通过手动将[CompilerGenerated]
添加到您选择的任何类型来强制误报。
您也可以使用action.Method.DeclaringType
,但由于所有捕获涉及目标实例,因此保留Target
检查非常有用:
bool isClosure = action.Target != null && Attribute.IsDefined(
action.Method.DeclaringType, typeof(CompilerGeneratedAttribute));