首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >代替(int)((List<T>.Enumerator*)(byte*)enumerator)->Current生成enumerator.Current

代替(int)((List<T>.Enumerator*)(byte*)enumerator)->Current生成enumerator.Current
EN

Stack Overflow用户
提问于 2020-01-10 09:07:39
回答 1查看 71关注 0票数 0

我目前正在开发一个API。

每当用户用某个属性标记一个类型时,我都希望创建一个新的List<int>字段并循环它,执行一些操作。

以下是一些相关代码:

代码语言:javascript
复制
TypeReference intTypeReference = moduleDefinition.ImportReference(typeof(int));

TypeReference listType = moduleDefinition.ImportReference(typeof(List<>));
GenericInstanceType intListType = listType.MakeGenericInstanceType(intTypeReference);

var numberList = 
    new FieldDefinition(
        name: "Numbers", 
        attributes: field.Attributes,
        fieldType: moduleDefinition.ImportReference(intListType));
generatedType.Fields.Add(numberList);

Type enumeratorType = typeof(List<>.Enumerator);

var enumeratorTypeReference = moduleDefinition.ImportReference(enumeratorType);
GenericInstanceType intEnumeratorType = enumeratorTypeReference.MakeGenericInstanceType(intTypeReference);

var enumeratorVariable = new VariableDefinition(intEnumeratorType);
convertMethod.Body.Variables.Add(enumeratorVariable);

ilProcessor.Emit(OpCodes.Ldarg_0); // this
ilProcessor.Emit(OpCodes.Ldfld, numberList); 

MethodReference getEnumeratorMethodReference =
    new MethodReference(
        name: "GetEnumerator",
        returnType: intEnumeratorType,
        declaringType: intListType)
    {
        HasThis = true
    };
ilProcessor.Emit(OpCodes.Callvirt, getEnumeratorMethodReference);
ilProcessor.Emit(OpCodes.Stloc, enumeratorVariable);

TypeDefinition enumeratorTypeDefinition = enumeratorTypeReference.Resolve();
MethodDefinition getCurrentMethod =
    enumeratorTypeDefinition.Properties.Single(p => p.Name == "Current").GetMethod;
MethodDefinition moveNextMethod = 
    enumeratorTypeDefinition.Methods.Single(m => m.Name == "MoveNext");

MethodReference getCurrentMethodReference = moduleDefinition.ImportReference(getCurrentMethod);
MethodReference moveNextMethodReference = moduleDefinition.ImportReference(moveNextMethod);

// Call enumerator.Current
ilProcessor.Emit(OpCodes.Ldloc, enumeratorVariable);
ilProcessor.Emit(OpCodes.Callvirt, getCurrentMethodReference);
// Store it inside currentVariable
ilProcessor.Emit(OpCodes.Stloc, currentVariable);
ilProcessor.Emit(OpCodes.Nop);

以下是相关的输出:

代码语言:javascript
复制
List<int>.Enumerator enumerator = Numbers.GetEnumerator();
int value = (int)((List<T>.Enumerator*)(byte*)enumerator)->Current;

List<int>.Enumerator enumerator = Numbers.GetEnumerator();是我想要的结果。然而,int value = (int)((List<T>.Enumerator*)(byte*)enumerator)->Current;显然不是我想要的。

我应该怎么做才能使输出变成int value = enumerator.Current,而不是目前那种不可读的混乱呢?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-01-10 09:30:37

List<T>.Enumerator是一种值类型。因此,您需要对enumerator变量的地址而不是它的值调用方法。

您也不能对值类型使用callvirt (尽管您可以执行受限的虚拟调用,这对于从object调用某些方法很有用)。您需要在这里使用call。这不是一个问题,因为值类型不能被子类化,所以您知道所调用的确切方法。

因此,你需要:

代码语言:javascript
复制
ilProcessor.Emit(OpCodes.Ldloca_S, enumeratorVariable);
ilProcessor.Emit(OpCodes.Call, getCurrentMethodReference);

这就解释了为什么要得到奇怪的反编译输出:反编译器知道只能在enumerator的地址上调用enumerator,但它也看到实际上是对值调用它,所以它将转换为将enumerator转换为指向List<T>.Enumerator的指针。

你可以看到那个论SharpLab

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59678485

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档