C# 从Mono.Cecil中的引用获取成员定义

C# 从Mono.Cecil中的引用获取成员定义,c#,.net,mono.cecil,C#,.net,Mono.cecil,我注意到某些类型的方法(例如泛型类型中的方法)中的字段或方法引用将是FieldReference类型,而不是FieldDefinition,尽管字段(或方法)位于同一模块中,属于同一类型。如何从该字段参考获取字段定义 我尝试了module.Import和module.MetadataResolver.Resolve,但两者都不起作用 这是问题的后续,但更一般 编辑: 一个简单的泛型类: public class HelperClass<T> { private int _so

我注意到某些类型的方法(例如泛型类型中的方法)中的字段或方法引用将是
FieldReference
类型,而不是
FieldDefinition
,尽管字段(或方法)位于同一模块中,属于同一类型。如何从该
字段参考
获取
字段定义

我尝试了
module.Import
module.MetadataResolver.Resolve
,但两者都不起作用

这是问题的后续,但更一般

编辑:

一个简单的泛型类:

public class HelperClass<T>
{
    private int _someInt;

    void SomeMethod(int i)
    {
        _someInt = i;
    }
}
通常情况下,
IL_000a
操作码的操作数应该是
FieldDefinition
,毕竟它在同一个模块中。但是因为
HelperClass
是泛型的,我想操作数是一个无法解析的
FieldReference
,所以我只希望比较全名来实际找到
FieldDefinition

在这种情况下,这不是什么大问题,但当引用指向其他泛型类型中的其他成员时,我相信有一种更好的方法来完成此操作,而不是枚举所有类型以找到定义

编辑:

HelperClass
来自运行时由
AssemblyDefinition.ReadAssembly
加载的模块,此时
.Resolve()
返回null,而不是返回
字段定义

更新:

事实证明,因为我正在更改泛型类型中字段的名称,所以引用正在中断,
Resolve()
返回null。仍在寻找合适的解决方案。

更新:

我已经更改了代码,将不同的类型划分为不同解决方案中的不同项目。不幸的是,我仍然无法重现这个问题,但如果它有帮助的话,我愿意继续尝试

我能够用以下代码解析类型引用。如果你能提供复制品的更多细节,我愿意再次尝试:-)

这是名为TargetLibrary.dll的程序集中的唯一类型。我用自己的解决方案编译了它,并将程序集复制到
C:\Temp

public class HelperClass<T>
{
    private int _someInt;

    void SomeMethod(int i)
    {
        _someInt = i;
    }
}
公共类帮助类
{
私人国际(someInt),;
无效方法(int i)
{
_someInt=i;
}
}
此代码位于另一个程序集中,该程序集在其自己的解决方案中编译为控制台exe文件

class Program
{
    static void Main(string[] args)
    {
        var module = AssemblyDefinition.ReadAssembly(@"C:\Temp\TargetLibrary.dll").MainModule;

        Console.WriteLine("For HelperClass<>");
        var helperClass = module.Types[1];
        var someMethod = helperClass.Methods[0];
        var someMethodBody = someMethod.Body;
        foreach (var instruction in someMethodBody.Instructions)
        {
            Console.WriteLine(
                "{0}\t{1}\t{2}",
                instruction.Offset,
                instruction.OpCode.Code,
                instruction.Operand == null ? "<null>" : string.Format("{0} / {1}", instruction.Operand.GetType().FullName, instruction.Operand.ToString()));

            var fieldReference = instruction.Operand as FieldReference;
            if (fieldReference != null)
            {
                var fieldDefinition = fieldReference.Resolve();
                Console.WriteLine(
                    "\t\tResolved field reference operand: {0} / {1}",
                    fieldDefinition.GetType().FullName,
                    fieldDefinition.ToString());
            }
        }
    }
}
类程序
{
静态void Main(字符串[]参数)
{
var module=AssemblyDefinition.ReadAssembly(@“C:\Temp\TargetLibrary.dll”).main模块;
Console.WriteLine(“用于HelperClass”);
var helperClass=module.Types[1];
var someMethod=helperClass.Methods[0];
var someMethodBody=someMethod.Body;
foreach(someMethodBody.Instructions中的var指令)
{
控制台写入线(
“{0}\t{1}\t{2}”,
指令。偏移,
指令.OpCode.Code,
指令.操作数==null?”:字符串.格式(“{0}/{1}”,指令.操作数.GetType().FullName,指令.操作数.ToString());
var fieldReference=指令。操作数作为fieldReference;
if(fieldReference!=null)
{
var fieldDefinition=fieldReference.Resolve();
控制台写入线(
“\t\t已解决的字段引用操作数:{0}/{1}”,
fieldDefinition.GetType().FullName,
fieldDefinition.ToString());
}
}
}
}
运行此命令将生成以下输出

For HelperClass<>
0       Ldarg_0 <null>
1       Ldarg_1 <null>
2       Stfld   Mono.Cecil.FieldReference / System.Int32 TargetLibrary.HelperClass`1<T>::_someInt
                Resolved field reference operand: Mono.Cecil.FieldDefinition / System.Int32 TargetLibrary.HelperClass`1::_someInt
7       Ret     <null>
HelperClass的

0 Ldarg\u 0
1 Ldarg_1
2 Stfld Mono.Cecil.FieldReference/System.Int32 TargetLibrary.HelperClass`1::\u someInt
已解析的字段引用操作数:Mono.Cecil.FieldDefinition/System.Int32 TargetLibrary.HelperClass`1::\u someInt
7网

对引用调用Resolve()是否无效?(即
var myFieldDefinition=myFieldReference.Resolve();
)@rileywhite-Nope,返回null。起初我认为它应该是一个定义,但我认为对泛型类型成员的引用在Cecil中的处理方式不同。你能发布复制你所看到的内容的代码吗?@rileywhite请查看编辑。谢谢!问题是,引用实际上来自加载的模块,我指的是在运行时加载的模块。当Resolve()返回null时,您的示例正在处理执行程序集中的泛型类型,我不知道为什么这样做,而另一个不行。Hmmm…似乎与引用关联的程序集解析器在定位程序集时遇到问题,这很奇怪,因为您已经使用了解析器来加载程序集。我有几分钟的时间再试试。我的想法完全正确。为了让事情更清楚,我使用
AssemblyDefinition.ReadAssembly
加载主模块,然后从那里开始。谢谢您的帮助。@mrahal,我已经根据您的反馈更新了代码。还有什么你能想到的,你可能会做不同的事情吗?我正在使用Mono.Cecil版本0.9.5.4,安装于Visual Studio 2013的NuGet和.NET 4.5中,以防出现问题。感谢所有帮助。我发现了这个问题,在我的另一个问题中,我声明我实际上在更改一些字段的名称。我发现当我这样做时,.Resolve方法返回null。我已经接受了你的回答,但你有没有建议如何做到这一点而不打破这个参考?当然,我可以想出一个解决办法,但我想先找一个简单的办法,然后再去另一个方向。
For HelperClass<>
0       Ldarg_0 <null>
1       Ldarg_1 <null>
2       Stfld   Mono.Cecil.FieldReference / System.Int32 TargetLibrary.HelperClass`1<T>::_someInt
                Resolved field reference operand: Mono.Cecil.FieldDefinition / System.Int32 TargetLibrary.HelperClass`1::_someInt
7       Ret     <null>