gpt4 book ai didi

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

转载 作者:太空宇宙 更新时间:2023-11-03 21:36:17 24 4
gpt4 key购买 nike

我必须使用 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;
}

我解决这个问题的想法是生成一个带反射的方法,将调用重定向到我的原始方法并返回 int

我需要知道如何执行 for 循环并使用 OpCodes 中断以在对类内的数组进行条件检查时重新创建方法。我搜索了教程,但没有找到比添加两个整数更进一步的教程。

编辑:忘了说了,我正在使用 IKVM.Reflection 并且 knownTypes 是一个 Type[] 数组。我写的方法是一种将覆盖抽象方法的方法。

最佳答案

这应该重现您指定的方法:

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!

反编译结果符合预期:

override int GetKeyImpl(Type obj0)
{
for (int i = 0; i < this.knownTypes.Length; i++)
{
if (this.knownTypes[i] == obj0)
return i;
}
return -1;
}

如果您有权访问 .NET Reflector,则有一个 Reflection.Emit Language Add-In你可能会感兴趣。或者,用 C# 代码编写原型(prototype),然后通过反汇编程序运行它以查看原始 IL。

如果可以将方法设为 static(并接受 knownTypes 作为参数或将其设为 static 字段),则您可以使用 LINQ 表达式树组成方法主体。不幸的是,您不能使用这种技术来组合实例方法体;它们必须是 static。示例:

var method = typeBuilder.DefineMethod(
"GetKeyImpl",
MethodAttributes.Private |
MethodAttributes.Static |
MethodAttributes.HideBySig);

var type = E.Parameter(typeof(Type), "type");
var knownTypes = E.Parameter(typeof(Type[]), "knownTypes");

var answer = E.Variable(typeof(int), "answer");
var i = E.Variable(typeof(int), "i");

var breakTarget = E.Label("breakTarget");
var continueTarget = E.Label("continueTarget");
var returnTarget = E.Label(typeof(int), "returnTarget");

var forLoop = E.Block(
new[] { i },
E.Assign(i, E.Constant(0)),
E.Loop(
E.Block(
E.IfThen(
E.GreaterThanOrEqual(i, E.ArrayLength(knownTypes)),
E.Break(breakTarget)),
E.IfThen(
E.Equal(E.ArrayIndex(knownTypes, i), type),
E.Return(returnTarget, i)),
E.Label(continueTarget),
E.PreIncrementAssign(i))),
E.Label(breakTarget));

var body = E.Lambda<Func<Type, Type[], int>>(
E.Block(
new[] { answer },
E.Assign(answer, E.Constant(-1)),
forLoop,
E.Label(returnTarget, answer)),
type,
knownTypes);

body.CompileToMethod(method);

return method;

上面的示例接受 knownTypes 作为第二个参数。重构为从静态字段中读取将是直截了当的。反编译结果同样符合预期:

private static int GetKeyImpl(Type type, Type[] knownTypes)
{
for (int i = 0; i < knownTypes.Length; i++)
{
if (knownTypes[i] == type)
return i;
}
return -1;
}

关于c# - 使用 for 循环和条件语句定义方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21629505/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com