我正在编写一个自定义规则来验证任何控件类型的构造函数调用initialize component。
但是当我遇到这两个边缘情况时:
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
那么我的指令是调用初始化组件隐藏我可以验证它是否实际被调用?
答案 0 :(得分:0)
在遍历构成构造函数的块时,请注意CS $&lt;&gt; 9__CachedAnonymousMethodDelegateb类型变量。该类实际上包含调用InitializeComponent的编译委托。
如果你想检查一下,检查方法的本地,找到访问编译器生成的类型,你会发现它只有一个方法。访问该方法以检查它是否调用Initialize Component。
问题是检测这些类型的唯一方法是按名称。 C#和VB.NET编译器使用不同的命名方案来存储这些匿名委托。