对于使用代码编织向C#添加混合器的项目,我将从源mixin类型的无参数实例构造函数克隆代码到目标类型中的构造函数。为此,我将构造函数划分为三个概念部分,这就是我所寻求的帮助。
以下是三部分:
其基本思想是将源构造函数复用到这些片段中。复用步骤还包括检查局部变量(stloc*和ldloc*),因此指令分离是正确的非常重要。调用基本构造函数的目标构造函数是代码克隆目标。每个方法都将将源的第1节克隆到其第1节中,并在其第3节中添加一个方法调用,该调用将调用一个新方法,该方法将在目标类型中包含源构造函数的第3节代码。(它被放入自己的方法中,主要是因为有可能出现多个退出点。)
我已经阅读过C#规范的实例构造函数部分,但是除了确认我正在看到的三个部分的有意存在之外,我认为它没有帮助。在这件事上,我有几个很有希望的错误开始,而不是尝试另一个坏策略,它通过了我的测试用例,然后一旦碰到我没有想到的事情就会窒息,我希望我能从有更好经验的人那里得到一些更好的输入。
我当前的“下一步”思想是循环执行查找ldarg.0的指令,然后检测下一个方法调用。如果下一个方法调用是一个基构造函数或链式构造函数,那么我可以调用这个第2节,在第1节之前使用指令,在第3节之后调用指令。不过,我担心指令可能并不总是有如此清晰的分离,我不知道如何才能确定这样的事情。
另一个想法是,由于规范明确规定变量初始化指令位于基或链式调用构造函数之前,因此查找设置本地字段的指令的结尾可能更可靠。不幸的是,我不知道怎样才是最好的方法。
下面是一个目标类型的例子,以及我正在寻找的构造函数的概念分解。
public class MultipleConstructorsTarget : MultipleConstructorsTargetBase
{
public MultipleConstructorsTarget()
{
var values = Tuple.Create(783535, "KNion wineofn oianweiof nqiognui ndf", new UriBuilder { Host = "j.k.l" });
this.OriginalUninitializedInt = values.Item1;
this.OriginalUninitializedString = values.Item2;
this.OriginalUninitializedObject = values.Item3;
}
public MultipleConstructorsTarget(int i) : this(i, "A iuohiogfniouhe uihui iu.", new UriBuilder { Host = "g.h.i" }) { }
public MultipleConstructorsTarget(int i, string j) : this(i, j, new UriBuilder { Host = "d.e.f" }) { }
public MultipleConstructorsTarget(int i, string j, UriBuilder k)
: base(i)
{
this.OriginalUninitializedInt = i;
this.OriginalUninitializedString = j;
this.OriginalUninitializedObject = k;
}
public int OriginalInitializedInt = 48685;
public string OriginalInitializedString = "Tion3lao ehiuawh iuh buib ld";
public UriBuilder OriginalInitializedObject = new UriBuilder { Host = "a.b.c" };
public int OriginalUninitializedInt;
public string OriginalUninitializedString;
public UriBuilder OriginalUninitializedObject;
}对于MultipleConstructorsTarget()
第1节
IL_0000: ldarg.0
IL_0001: ldc.i4 0xbe2d
IL_0006: stfld int32 Bix.Mixers.Fody.TestMixinTargets.MultipleConstructorsTarget::OriginalInitializedInt
IL_000b: ldarg.0
IL_000c: ldstr "Tion3lao ehiuawh iuh buib ld"
IL_0011: stfld string Bix.Mixers.Fody.TestMixinTargets.MultipleConstructorsTarget::OriginalInitializedString
IL_0016: ldarg.0
IL_0017: newobj instance void [System]System.UriBuilder::.ctor()
IL_001c: stloc.2
IL_001d: ldloc.2
IL_001e: ldstr "a.b.c"
IL_0023: callvirt instance void [System]System.UriBuilder::set_Host(string)
IL_0028: ldloc.2
IL_0029: stfld class [System]System.UriBuilder Bix.Mixers.Fody.TestMixinTargets.MultipleConstructorsTarget::OriginalInitializedObject第2节
IL_002e: ldarg.0
IL_002f: call instance void Bix.Mixers.Fody.TestMixinTargets.MultipleConstructorsTargetBase::.ctor()第3节
IL_0034: ldc.i4 0xbf4af
IL_0039: ldstr "KNion wineofn oianweiof nqiognui ndf"
IL_003e: newobj instance void [System]System.UriBuilder::.ctor()
IL_0043: stloc.1
IL_0044: ldloc.1
IL_0045: ldstr "j.k.l"
IL_004a: callvirt instance void [System]System.UriBuilder::set_Host(string)
IL_004f: ldloc.1
IL_0050: call class [mscorlib]System.Tuple`3<!!0,!!1,!!2> [mscorlib]System.Tuple::Create<int32,string,class [System]System.UriBuilder>(!!0, !!1, !!2)
IL_0055: stloc.0
IL_0056: ldarg.0
IL_0057: ldloc.0
IL_0058: callvirt instance !0 class [mscorlib]System.Tuple`3<int32,string,class [System]System.UriBuilder>::get_Item1()
IL_005d: stfld int32 Bix.Mixers.Fody.TestMixinTargets.MultipleConstructorsTarget::OriginalUninitializedInt
IL_0062: ldarg.0
IL_0063: ldloc.0
IL_0064: callvirt instance !1 class [mscorlib]System.Tuple`3<int32,string,class [System]System.UriBuilder>::get_Item2()
IL_0069: stfld string Bix.Mixers.Fody.TestMixinTargets.MultipleConstructorsTarget::OriginalUninitializedString
IL_006e: ldarg.0
IL_006f: ldloc.0
IL_0070: callvirt instance !2 class [mscorlib]System.Tuple`3<int32,string,class [System]System.UriBuilder>::get_Item3()
IL_0075: stfld class [System]System.UriBuilder Bix.Mixers.Fody.TestMixinTargets.MultipleConstructorsTarget::OriginalUninitializedObject
IL_007a: ret对于MultipleConstructorsTarget(int i)
第1节
(空)
第2节
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: ldstr "A iuohiogfniouhe uihui iu."
IL_0007: newobj instance void [System]System.UriBuilder::.ctor()
IL_000c: stloc.0
IL_000d: ldloc.0
IL_000e: ldstr "g.h.i"
IL_0013: callvirt instance void [System]System.UriBuilder::set_Host(string)
IL_0018: ldloc.0
IL_0019: call instance void Bix.Mixers.Fody.TestMixinTargets.MultipleConstructorsTarget::.ctor(int32, string, class [System]System.UriBuilder)第3节
IL_001e: ret对于MultipleConstructorsTarget(int i, string j)
第1节
(空)
第2节
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: ldarg.2
IL_0003: newobj instance void [System]System.UriBuilder::.ctor()
IL_0008: stloc.0
IL_0009: ldloc.0
IL_000a: ldstr "d.e.f"
IL_000f: callvirt instance void [System]System.UriBuilder::set_Host(string)
IL_0014: ldloc.0
IL_0015: call instance void Bix.Mixers.Fody.TestMixinTargets.MultipleConstructorsTarget::.ctor(int32, string, class [System]System.UriBuilder)第3节
IL_001a: ret对于MultipleConstructorsTarget(int i, string j, UriBuilder k)
第1节
IL_0000: ldarg.0
IL_0001: ldc.i4 0xbe2d
IL_0006: stfld int32 Bix.Mixers.Fody.TestMixinTargets.MultipleConstructorsTarget::OriginalInitializedInt
IL_000b: ldarg.0
IL_000c: ldstr "Tion3lao ehiuawh iuh buib ld"
IL_0011: stfld string Bix.Mixers.Fody.TestMixinTargets.MultipleConstructorsTarget::OriginalInitializedString
IL_0016: ldarg.0
IL_0017: newobj instance void [System]System.UriBuilder::.ctor()
IL_001c: stloc.0
IL_001d: ldloc.0
IL_001e: ldstr "a.b.c"
IL_0023: callvirt instance void [System]System.UriBuilder::set_Host(string)
IL_0028: ldloc.0
IL_0029: stfld class [System]System.UriBuilder Bix.Mixers.Fody.TestMixinTargets.MultipleConstructorsTarget::OriginalInitializedObject第2节
IL_002e: ldarg.0
IL_002f: ldarg.1
IL_0030: call instance void Bix.Mixers.Fody.TestMixinTargets.MultipleConstructorsTargetBase::.ctor(int32)第3节
IL_0035: ldarg.0
IL_0036: ldarg.1
IL_0037: stfld int32 Bix.Mixers.Fody.TestMixinTargets.MultipleConstructorsTarget::OriginalUninitializedInt
IL_003c: ldarg.0
IL_003d: ldarg.2
IL_003e: stfld string Bix.Mixers.Fody.TestMixinTargets.MultipleConstructorsTarget::OriginalUninitializedString
IL_0043: ldarg.0
IL_0044: ldarg.3
IL_0045: stfld class [System]System.UriBuilder Bix.Mixers.Fody.TestMixinTargets.MultipleConstructorsTarget::OriginalUninitializedObject
IL_004a: ret我正在使用Mono.Cecil进行我所有的IL读写。如果您感兴趣,可以在Bix.Mixers上找到https://github.com/rileywhite/Bix.Mixers.Fody的项目代码。这个问题涉及的特定文件位于https://github.com/rileywhite/Bix.Mixers.Fody/blob/master/src/Bix.Mixers/Fody/ILCloning/ConstructorMultiplexer.cs。
发布于 2014-11-01 19:58:23
一种似乎有效的策略是通过构造函数指令枚举,将它们分组如下:
一旦确定了一个组,就会检查组中的最后一个指令。如果它是一个调用指令,并且操作数是一个基构造函数或链式构造函数,那么这个组被标识为第2节,这意味着前面的指令是第1节,其余的指令是第3节。
下面的代码,给定要开始查看的索引,根据这些规则标识一组指令。
public static bool TryGetNext(IList<Instruction> sourceInstructions, int firstIndex, out InstructionGroup instructionGroup)
{
Contract.Requires(sourceInstructions != null);
if (firstIndex < 0 || firstIndex >= sourceInstructions.Count)
{
instructionGroup = null;
return false;
}
var instructions = new List<Instruction>();
var instruction = sourceInstructions[firstIndex];
instructions.Add(instruction);
int lastIndex;
if (instruction.OpCode.Code != Code.Ldarg_0) { lastIndex = firstIndex; }
else
{
int i;
// calls into base and chained constructors start like this
// so we'll look for the next call instruction or any instruction where the next instruction is another ldarg.0
// meaning that the stack was cleared at some point
// there is no assumption that this grouping is generally useful, but the hope is that it will catch constructor calls in this specific case
var isLastInstructionFound = false;
for (i = firstIndex + 1; !isLastInstructionFound && i < sourceInstructions.Count; i++)
{
instruction = sourceInstructions[i];
instructions.Add(instruction);
if (instruction.OpCode.Code == Code.Call ||
instruction.OpCode.Code == Code.Callvirt ||
instruction.OpCode.Code == Code.Calli ||
(instruction.Next != null && instruction.Next.OpCode.Code == Code.Ldarg_0))
{
isLastInstructionFound = true;
}
}
lastIndex = i - 1;
}
instructionGroup = new InstructionGroup(firstIndex, lastIndex, instructions);
return true;
}如果您感兴趣,可以在https://github.com/rileywhite/Bix.Mixers.Fody/blob/0.1.7/src/Bix.Mixers/Fody/ILCloning/ConstructorMultiplexer.cs上看到完整的代码。
尽管这似乎是可行的,但我不会选择这个作为最终答案,因为这仍然只是另一个启发。我很想从更有经验的人那里得到一个真正的答案。
https://stackoverflow.com/questions/26644148
复制相似问题