2010-09-07 49 views
0

我在寫一個自定義規則來驗證任何控件類型的構造函數調用初始化組件。如何將自定義規則的方法調用傳遞給自反操作中的Action,Func或Delegate?

但是,當我打這兩個邊緣情況:

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(); 
    } 

我似乎無法走路初始化調用看到的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

那麼我的指令調用初始化組件隱藏,我可以驗證它實際上被稱爲?

+0

.Net4.0 vs2010,規則在vs2010團隊工具\靜態分析工具中繼承'Microsoft.FxCop.Sdk.BaseIntrospectionRule' – Maslow 2010-09-07 16:03:09

+0

您真的想允許通過委託來調用InitializeComponent嗎?如果沒有任何實際的補償收益,這種方法的性能會受到影響,那麼爲什麼「拉伸」規則以允許該方案? – 2010-09-08 18:39:24

回答

0

在構建構造函數的塊時,注意CS $ <> 9__CachedAnonymousMethodDelegateb類型變量。該類實際上包含調用InitializeComponent的已編譯委託。

如果你想檢查這個,檢查方法的本地化,找到訪問編譯器生成的類型,你會發現它只有一個方法。訪問該方法來檢查它是否調用Initialize Component。

問題是檢測這些類的唯一方法是按名稱。而C#和VB.NET編譯器使用不同的命名方案來存儲這些匿名代理。

相關問題