如何将方法调用传递到自检器中的 Action、Func 或 Delegate 以获取自定义规则?

Posted

技术标签:

【中文标题】如何将方法调用传递到自检器中的 Action、Func 或 Delegate 以获取自定义规则?【英文标题】:How can I walk the method call to an Action, Func, or Delegate in introspector for a custom rule? 【发布时间】:2010-09-07 16:01:35 【问题描述】:

我正在编写一个自定义规则来验证任何控件类型的构造函数调用初始化组件。

但是当我遇到这两种极端情况时:

public Form1(int? testInt,bool testBool,bool testBool2)
        : this(false)
    
        Action init = ( ) => InitializeComponent( );
        init();
    
    public Form1(int? testInt, bool testBool, bool? testBool2)
        : this(false)
    
        Action init = InitializeComponent;
        init( );
    

我似乎无法通过 init 调用看到在这些构造函数中调用了 initializeComponent。我知道这是一个极端情况,不太可能发生,但我想学习如何去做。

反射器 IL 如下所示:

.method public hidebysig specialname rtspecialname instance void .ctor(valuetype [mscorlib]System.Nullable`1<int32> testInt, bool testBool, bool testBool2) cil managed

.maxstack 3
.locals init (
    [0] class [mscorlib]System.Action init,
    [1] class [mscorlib]System.Action CS$<>9__CachedAnonymousMethodDelegateb)
L_0000: ldnull 
L_0001: stloc.1 
L_0002: ldarg.0 
L_0003: ldc.i4.0 
L_0004: call instance void TestLibrary.Form1::.ctor(bool)
L_0009: nop 
L_000a: nop 
L_000b: ldloc.1 
L_000c: brtrue.s L_001d
L_000e: ldarg.0 
L_000f: ldftn instance void TestLibrary.Form1::<.ctor>b__a()
L_0015: newobj instance void [mscorlib]System.Action::.ctor(object, native int)
L_001a: stloc.1 
L_001b: br.s L_001d
L_001d: ldloc.1 
L_001e: stloc.0 
L_001f: ldloc.0 
L_0020: callvirt instance void [mscorlib]System.Action::Invoke()
L_0025: nop 
L_0026: nop 
L_0027: ret 



.method public hidebysig specialname rtspecialname instance void .ctor(valuetype [mscorlib]System.Nullable`1<int32> testInt, bool testBool, valuetype [mscorlib]System.Nullable`1<bool> testBool2) cil managed

.maxstack 3
.locals init (
    [0] class [mscorlib]System.Action init)
L_0000: ldarg.0 
L_0001: ldc.i4.0 
L_0002: call instance void TestLibrary.Form1::.ctor(bool)
L_0007: nop 
L_0008: nop 
L_0009: ldarg.0 
L_000a: ldftn instance void TestLibrary.Form1::InitializeComponent()
L_0010: newobj instance void [mscorlib]System.Action::.ctor(object, native int)
L_0015: stloc.0 
L_0016: ldloc.0 
L_0017: callvirt instance void [mscorlib]System.Action::Invoke()
L_001c: nop 
L_001d: nop 
L_001e: ret 

我正在像这样走构造函数:

        private Dictionary<Method, bool> _methodContainsInitCall;
public void VisitConstructorsRecursive(Method method, Method initializer)
    
        Debug.Assert(_methodContainsInitCall.ContainsKey(method));
        var toVisit = new List<Method>( );
        foreach (var instruction in method.Instructions.Where(x => x.OpCode==OpCode.Call || x.OpCode== OpCode.Callvirt))
        

            if (instruction.Value is Method)
            
                //&&((Method)instruction.Value).FullName.Contains(".#ctor")
                var callMethod =(Method)instruction.Value;
                if (callMethod.FullName.StartsWith("System.Windows.Forms.Form.#ctor"))
                    continue;
                if (callMethod.IsStatic==false) //can not call instance method InitializeComponent in static method
                
                    toVisit.Add(callMethod);
                

                //
                //TestLibrary.Form1.#ctor(System.String)
            
            if (instruction.Value is Method&&((Method)instruction.Value).FullName.EndsWith(".InitializeComponent"))
            
                if (_constructorFoundInitializeCall.ContainsKey(method))
                    _constructorFoundInitializeCall[method]=true;
                _methodContainsInitCall[method]=true;
                return;
            

        
        foreach (var methodCall in toVisit)
        
            if (_methodContainsInitCall.ContainsKey(methodCall))
            
                if (_methodContainsInitCall[methodCall])
                
                    _constructorFoundInitializeCall[initializer]=true;
                    return;
                
            
            else
            
                _methodContainsInitCall.Add(methodCall, false);
                VisitConstructorsRecursive(methodCall, initializer);
            


        
    

当对Action.Invoke() 的虚拟调用发生时,它被标记为虚拟和method.Instructions.Count ==0 以及method.Body.Count==0

那么我调用初始化组件隐藏的指令在哪里,我可以验证它实际上被调用了?

【问题讨论】:

.Net4.0 vs2010,规则继承vs2010团队工具\静态分析工具中的Microsoft.FxCop.Sdk.BaseIntrospectionRule 您真的要允许通过委托调用 InitializeComponent 吗?这种方法会影响性能,但没有任何真正的补偿性好处,那么为什么要“拉伸”规则以允许该场景呢? 【参考方案1】:

在遍历构成构造函数的块时,请注意 CS$9__CachedAnonymousMethodDelegateb 类型变量。该类实际上包含调用 InitializeComponent 的已编译委托。

如果你想检查这个,检查方法的局部变量,找到访问编译器生成的类型,你会发现它只有一个方法。访问该方法,检查它是否调用了 Initialize Component。

问题在于,检测这些类型的类的唯一方法是通过名称。并且 C# 和 VB.NET 编译器使用不同的命名方案来存储这些匿名委托。

【讨论】:

以上是关于如何将方法调用传递到自检器中的 Action、Func 或 Delegate 以获取自定义规则?的主要内容,如果未能解决你的问题,请参考以下文章

如何将文本字段数据从 Struts 2 中的 ajax 操作传递到原始调用 .jsp?

如何将正确的 Url.Action 传递给 JQuery 方法而没有额外的 & 号麻烦?

将带有变量的闭包传递给 Laravel 查询构建器中的 where 方法

如何将null值传递给简单注入器中的构造函数?

如何将一个动作传递到视图中,并在按钮的动作中调用它?

如何在 asp.net MVC 中使用 RedirectToAction 将模型从一个 Action 方法传递到另一个?尽管我发送了一个填充模型,但我得到的是空模型