【问题标题】:Create an Instruction for Type为类型创建指令
【发布时间】:2025-12-27 13:40:06
【问题描述】:

使用 Mono.Cecil,给定这个方法

private Instruction LoadOnStack(MetadataType type, object value)
{
    switch (type)
    {
        case MetadataType.String:
            return _processor.Create(OpCodes.Ldstr, (string) value);
        case MetadataType.Int32:
            return _processor.Create(OpCodes.Ldc_I4, (Int32) value);
        case MetadataType.Int64:
            return _processor.Create(OpCodes.Ldc_I8, (Int64) value);
        case MetadataType.Boolean:
            return _processor.Create(OpCodes.Ldc_I4, (bool) value ? 1 : 0);                
    }

    throw new NotSupportedException("Not a supported primitve parameter type: " + type);
}

value 的类型为Type 时,如何创建可以加载valueInstruction

我注意到当valueType 类型时,我可以像这样对其进行测试:

if (value is TypeReference)
    return _processor.Create(???, ???);

但我无法弄清楚我需要传递给Create 以获取正确加载的值。

编辑:

使用这个:

if (value is TypeReference)
    return _processor.Create(OpCodes.Ldobj, type.Resolve());

让我更近一步。它似乎接受类型。但是当我尝试编写程序集时,它会出错:

System.ArgumentException : Member 'System.Type' is declared in another module and needs to be imported

【问题讨论】:

  • 我不熟悉 il 可用的内容;反射是一种选择吗?您可以在_processor 中搜索Create 方法,其第二个参数的类型为Type?或者,所有东西都可以装箱到一个对象...?
  • 您是否尝试将Type 类型的对象实例加载到堆栈中?
  • @object88 在这种情况下,反射不是一个选项。而OpCodes 没有Type 的条目。我试过OpCodes.LdobjOpCodes.Ldind_Ref 和其他一些我不记得了
  • @cubrr 这是个好问题。我相信是的。它是来自 Attribute 的命名命名参数,使用 typeof 运算符分配。
  • 尝试首先使用您的类型发出ldtoken,然后发出对Type.GetTypeFromHandle的调用

标签: c# il mono.cecil fody


【解决方案1】:

正如@cubrr 已经指出的那样:

我们将此代码用于MethodBoundaryAspect.Fody

private IList<Instruction> LoadValueOnStack(TypeReference parameterType, object value, ModuleDefinition module)
{
    if (parameterType.IsPrimitive || (parameterType.FullName == "System.String"))
        return new List<Instruction> {LoadPrimitiveConstOnStack(parameterType.MetadataType, value)};

    if (parameterType.IsValueType) // enum
    {
        var enumUnderlyingType = GetEnumUnderlyingType(parameterType.Resolve());
        return new List<Instruction> {LoadPrimitiveConstOnStack(enumUnderlyingType.MetadataType, value)};
    }

    if (parameterType.FullName == "System.Type")
    {
        var typeName = value.ToString();
        var typeReference = module.GetType(typeName, true);

        var typeTypeRef = _referenceFinder.GetTypeReference(typeof (Type));
        var methodReference = _referenceFinder.GetMethodReference(typeTypeRef, md => md.Name == "GetTypeFromHandle");

        var instructions = new List<Instruction>
        {
            _processor.Create(OpCodes.Ldtoken, typeReference),
            _processor.Create(OpCodes.Call, methodReference)
        };

        return instructions;
    }

    throw new NotSupportedException("Parametertype: " + parameterType);
}

private Instruction LoadPrimitiveConstOnStack(MetadataType type, object value)
{
    switch (type)
    {
        case MetadataType.String:
            return _processor.Create(OpCodes.Ldstr, (string) value);
        case MetadataType.Int32:
            return _processor.Create(OpCodes.Ldc_I4, (int) value);
        case MetadataType.Int64:
            return _processor.Create(OpCodes.Ldc_I8, (long) value);
        case MetadataType.Boolean:
            return _processor.Create(OpCodes.Ldc_I4, (bool) value ? 1 : 0);
    }

    throw new NotSupportedException("Not a supported primitive parameter type: " + type);
}

private static TypeReference GetEnumUnderlyingType(TypeDefinition self)
{
    foreach (var field in self.Fields)
    {
        if (field.Name == "value__")
            return field.FieldType;
    }

    throw new ArgumentException();
} 

类 ReferenceFinder 所在的位置:

private readonly ModuleDefinition _moduleDefinition;

public ReferenceFinder(ModuleDefinition moduleDefinition)
{
    _moduleDefinition = moduleDefinition;
}

public MethodReference GetMethodReference(Type declaringType, Func<MethodDefinition, bool> predicate)
{
    return GetMethodReference(GetTypeReference(declaringType), predicate);
}

public MethodReference GetMethodReference(TypeReference typeReference, Func<MethodDefinition, bool> predicate)
{
    var typeDefinition = typeReference.Resolve();

    MethodDefinition methodDefinition;
    do
    {
        methodDefinition = typeDefinition.Methods.FirstOrDefault(predicate);
        typeDefinition = typeDefinition.BaseType == null 
            ? null 
            : typeDefinition.BaseType.Resolve();
    } while (methodDefinition == null && typeDefinition != null);

    return _moduleDefinition.Import(methodDefinition);
}

public TypeReference GetTypeReference(Type type)
{
    return _moduleDefinition.Import(type);
}

【讨论】: