C# 使用for循环和条件语句定义方法

C# 使用for循环和条件语句定义方法,c#,reflection,reflection.emit,ikvm,C#,Reflection,Reflection.emit,Ikvm,我必须定义一个带有Reflection.Emit的方法,这相当复杂,因为我必须在字段上执行for循环,并且有一个带break和return的条件。我想用反射重新创建的方法在常规代码中如下所示: override int GetKeyImpl(Type obj0) { int answer = -1; for(int i = 0; i < knownTypes.length; i++){ if(knowntypes[i] == obj0){

我必须定义一个带有
Reflection.Emit
的方法,这相当复杂,因为我必须在字段上执行for循环,并且有一个带break和return的条件。我想用反射重新创建的方法在常规代码中如下所示:

override int GetKeyImpl(Type obj0)
{
    int answer = -1;
    for(int i = 0; i < knownTypes.length; i++){
          if(knowntypes[i] == obj0){
                answer = i;
                break;
          }
    }
    return answer;
} 
override int GetKeyImpl(类型obj0)
{
int-answer=-1;
for(int i=0;i
我解决这个问题的想法是生成一个带有反射的方法,该方法将调用重定向到原始方法并返回
int

我需要知道如何在对类中的数组执行条件检查时使用操作码执行for循环和break来重新创建方法。我已经搜索了教程,但没有找到任何比添加两个int更进一步的教程


编辑:忘了提了,我使用的是IKVM.Reflection和knownTypes是一个类型为[]的数组。im编写的方法将覆盖抽象方法

这将重现您指定的方法:

TypeBuilder type = /* ... */;
FieldInfo knownFields = /* ... */;

// Finding dependencies via reflection
var baseMethod = type.BaseType.GetMethod(
    "GetKeyImpl",
    BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

var typeEqualsOperator = typeof(Type).GetMethod(
    "op_Equality",
    BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic,
    null,
    new[] { typeof(Type), typeof(Type) },
    null);

// Declaring the method
var getKeyImpl = type.DefineMethod(
    baseMethod.Name,
    baseMethod.Attributes & ~(MethodAttributes.Abstract |
                              MethodAttributes.NewSlot));

// Setting return type
getKeyImpl.SetReturnType(typeof(int));

// Adding parameters
getKeyImpl.SetParameters(typeof(Type));
getKeyImpl.DefineParameter(1, ParameterAttributes.None, "obj0");

// Override the base method
type.DefineMethodOverride(getKeyImpl, baseMethod);

var il = getKeyImpl.GetILGenerator();

// Preparing locals
var answer = il.DeclareLocal(typeof(int));
var i = il.DeclareLocal(typeof(int));

// Preparing labels
var loopCondition = il.DefineLabel();
var loopIterator = il.DefineLabel();
var returnLabel = il.DefineLabel();
var loopBody = il.DefineLabel();

// Writing body

// answer = -1
il.Emit(OpCodes.Ldc_I4_M1);
il.Emit(OpCodes.Stloc, answer);

// i = 0
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Stloc, i);

// jump to loop condition
il.Emit(OpCodes.Br_S, loopCondition);

// begin loop body
il.MarkLabel(loopBody);

// if (obj0 != knownTypes[i]) continue
il.Emit(OpCodes.Ldarg_0); // omit if 'knownTypes' is static
il.Emit(OpCodes.Ldfld, knownTypes); // use 'Ldsfld' if 'knownTypes' is static
il.Emit(OpCodes.Ldloc, i);
il.Emit(OpCodes.Ldelem_Ref);
il.Emit(OpCodes.Ldarg_1); // use 'Ldarg_0' if 'knownTypes' is static
il.Emit(OpCodes.Call, typeEqualsOperator);
il.Emit(OpCodes.Brfalse_S, loopIterator);

// answer = i; jump to return
il.Emit(OpCodes.Ldloc, i);
il.Emit(OpCodes.Stloc, answer);
il.Emit(OpCodes.Br_S, returnLabel);

// begin loop iterator
il.MarkLabel(loopIterator);

// i = i + 1
il.Emit(OpCodes.Ldloc, i);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Add);
il.Emit(OpCodes.Stloc, i);

// begin loop condition
il.MarkLabel(loopCondition);

// if (i < knownTypes.Length) jump to loop body
il.Emit(OpCodes.Ldloc, i);
il.Emit(OpCodes.Ldarg_0); // omit if 'knownTypes' is static
il.Emit(OpCodes.Ldfld, knownTypes); // use 'Ldsfld' if 'knownTypes' is static
il.Emit(OpCodes.Ldlen);
il.Emit(OpCodes.Conv_I4);
il.Emit(OpCodes.Blt_S, loopBody);

// return answer
il.MarkLabel(returnLabel);
il.Emit(OpCodes.Ldloc, answer);
il.Emit(OpCodes.Ret);

// Finished!
上面的示例接受
knownTypes
作为第二个参数。重构以从静态字段读取将是非常简单的。反编译结果与预期一样:

override int GetKeyImpl(Type obj0)
{
    for (int i = 0; i < this.knownTypes.Length; i++)
    {
        if (this.knownTypes[i] == obj0)
            return i;
    }
    return -1;
}
private static int GetKeyImpl(Type type, Type[] knownTypes)
{
    for (int i = 0; i < knownTypes.Length; i++)
    {
        if (knownTypes[i] == type)
            return i;
    }
    return -1;
}
private static int GetKeyImpl(类型,类型[]knownTypes)
{
for(int i=0;i
这将重现您指定的方法:

TypeBuilder type = /* ... */;
FieldInfo knownFields = /* ... */;

// Finding dependencies via reflection
var baseMethod = type.BaseType.GetMethod(
    "GetKeyImpl",
    BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

var typeEqualsOperator = typeof(Type).GetMethod(
    "op_Equality",
    BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic,
    null,
    new[] { typeof(Type), typeof(Type) },
    null);

// Declaring the method
var getKeyImpl = type.DefineMethod(
    baseMethod.Name,
    baseMethod.Attributes & ~(MethodAttributes.Abstract |
                              MethodAttributes.NewSlot));

// Setting return type
getKeyImpl.SetReturnType(typeof(int));

// Adding parameters
getKeyImpl.SetParameters(typeof(Type));
getKeyImpl.DefineParameter(1, ParameterAttributes.None, "obj0");

// Override the base method
type.DefineMethodOverride(getKeyImpl, baseMethod);

var il = getKeyImpl.GetILGenerator();

// Preparing locals
var answer = il.DeclareLocal(typeof(int));
var i = il.DeclareLocal(typeof(int));

// Preparing labels
var loopCondition = il.DefineLabel();
var loopIterator = il.DefineLabel();
var returnLabel = il.DefineLabel();
var loopBody = il.DefineLabel();

// Writing body

// answer = -1
il.Emit(OpCodes.Ldc_I4_M1);
il.Emit(OpCodes.Stloc, answer);

// i = 0
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Stloc, i);

// jump to loop condition
il.Emit(OpCodes.Br_S, loopCondition);

// begin loop body
il.MarkLabel(loopBody);

// if (obj0 != knownTypes[i]) continue
il.Emit(OpCodes.Ldarg_0); // omit if 'knownTypes' is static
il.Emit(OpCodes.Ldfld, knownTypes); // use 'Ldsfld' if 'knownTypes' is static
il.Emit(OpCodes.Ldloc, i);
il.Emit(OpCodes.Ldelem_Ref);
il.Emit(OpCodes.Ldarg_1); // use 'Ldarg_0' if 'knownTypes' is static
il.Emit(OpCodes.Call, typeEqualsOperator);
il.Emit(OpCodes.Brfalse_S, loopIterator);

// answer = i; jump to return
il.Emit(OpCodes.Ldloc, i);
il.Emit(OpCodes.Stloc, answer);
il.Emit(OpCodes.Br_S, returnLabel);

// begin loop iterator
il.MarkLabel(loopIterator);

// i = i + 1
il.Emit(OpCodes.Ldloc, i);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Add);
il.Emit(OpCodes.Stloc, i);

// begin loop condition
il.MarkLabel(loopCondition);

// if (i < knownTypes.Length) jump to loop body
il.Emit(OpCodes.Ldloc, i);
il.Emit(OpCodes.Ldarg_0); // omit if 'knownTypes' is static
il.Emit(OpCodes.Ldfld, knownTypes); // use 'Ldsfld' if 'knownTypes' is static
il.Emit(OpCodes.Ldlen);
il.Emit(OpCodes.Conv_I4);
il.Emit(OpCodes.Blt_S, loopBody);

// return answer
il.MarkLabel(returnLabel);
il.Emit(OpCodes.Ldloc, answer);
il.Emit(OpCodes.Ret);

// Finished!
上面的示例接受
knownTypes
作为第二个参数。重构以从静态字段读取将是非常简单的。反编译结果与预期一样:

override int GetKeyImpl(Type obj0)
{
    for (int i = 0; i < this.knownTypes.Length; i++)
    {
        if (this.knownTypes[i] == obj0)
            return i;
    }
    return -1;
}
private static int GetKeyImpl(Type type, Type[] knownTypes)
{
    for (int i = 0; i < knownTypes.Length; i++)
    {
        if (knownTypes[i] == type)
            return i;
    }
    return -1;
}
private static int GetKeyImpl(类型,类型[]knownTypes)
{
for(int i=0;i
解决如何为方法生成IL的最简单方法是创建一个简单的控制台应用程序,该应用程序中包含您的方法。然后构建并运行它,查看组成该方法所需的IL指令


一旦您看到了说明,编写代码以发出必要的操作码应该不会太困难。

解决如何为方法生成IL的最简单方法是创建一个简单的控制台应用程序,该应用程序中包含您的方法。然后构建并运行它,查看组成该方法所需的IL指令


一旦可以看到指令,编写代码以发出必要的
操作码应该不会太困难。

如果可以将其重构为静态方法(其中
knowntypes
是参数或静态成员),则可以使用LINQ表达式树构建方法体,然后使用
表达式.CompileToMethod()
将其编译为
MethodBuidler
。这比手动发出IL更容易。如果可以将其重构为静态方法(其中
knowntypes
是参数或静态成员),则可以使用LINQ表达式树构建方法体,然后使用
expression.CompileToMethod()
将其编译为
MethodBuidler
。这比手动发送IL更容易。你的第一个答案似乎接近我要寻找的解决方案。我几乎完成了,但因为我使用的是IKVM.Reflection操作类型EqualsOperator不起作用。我需要自己解决这个问题。谢谢你的支持。我不熟悉那个库,但是
object.Equals(object,object)
或者
object.ReferenceEquals(object,object)
行吗?如果是这样,您只需将赋值更新为
typeEqualsOperator
,无需进行其他更改。更新我的答案以显示如何正确声明覆盖。好的,我马上就完成了。根据您的建议,在dotPeek中观察时,输出代码的结果如下:
int-TypeModel.GetKeyImpl([in]Type obj0){int-num=-1;for(int-index=0;index
,我不知道为什么它会说++索引,而应该是index++。@DenisDik
++index
index++
是该字节码的有效表示形式,它不会将结果推送到堆栈上(相当于
index=index+1
)。在整理代码时,反编译器可以自由选择它喜欢的任何增量形式。您的第一个答案似乎接近于我所寻找的解决方案。我几乎完成了,但因为我使用的是IKVM.Reflection操作类型EqualsOperator不起作用。我需要自己解决这个问题。谢谢你的支持。我不熟悉那个库,但是
object.Equals(object,object)
或者
object.ReferenceEquals(object,object)
行吗?如果是这样,您只需将赋值更新为
typeEqualsOperator
,无需进行其他更改。更新我的答案以显示如何正确声明覆盖。好的,我马上就完成了。根据您的建议,在dotPeek中观察时,输出代码的结果如下:
int-TypeModel.GetKeyImpl([in]Type obj0){int-num=-1;for(int-index=0;index
,我不知道为什么它会说++索引,而应该是index++。@DenisDik
++index
index++
是该字节码的有效表示形式,它不会将结果推送到堆栈上(相当于
index=index+1
)。反编译器可以自由选择whiche