从 Mono.Cecil 中的引用获取成员定义
Get member definition from reference in Mono.Cecil
我注意到某些类型的方法(例如泛型方法)中的字段或方法引用将是 FieldReference
类型,而不是 FieldDefinition
,尽管字段(或方法)在同一模块中,在同一类型中。我怎样才能从这个FieldReference
得到FieldDefinition
?
我尝试了 module.Import
和 module.MetadataResolver.Resolve
,但都不起作用。
跟进 this 问题,但更笼统。
编辑:
一个简单的通用类:
public class HelperClass<T>
{
private int _someInt;
void SomeMethod(int i)
{
_someInt = i;
}
}
SomeMethod
的正文包含:
...
IL_0008: ldarg.0
IL_0009: ldarg.1
IL_000a: stfdl System.Int32 HelperClass`1<T>::_someInt
....
IL_000a
操作码的操作数通常应该是 FieldDefinition
,毕竟它在同一个模块中。但是因为我想 HelperClass
是通用的,操作数是一个无法解析的 FieldReference
,我只能希望比较全名以实际找到 FieldDefinition
。
在这种情况下,这不是什么大问题,但是当引用是对其他泛型类型中的其他成员时,我相信有比枚举所有类型来查找更好的方法定义。
编辑:
HelperClass<>
来自 AssemblyDefinition.ReadAssembly
在运行时加载的模块,即 .Resolve()
returns null 而不是返回 FieldDefinition
.
更新:
事实证明,因为我正在更改通用类型中的字段名称,所以引用中断并且 Resolve()
返回 null。仍在为 this one.
寻找合适的解决方案
更新:
我更改了代码以将类型分离到不同解决方案中的不同项目中。不幸的是,我仍然无法重现该问题,但如果有帮助,我愿意继续尝试。
我可以使用以下代码解析类型引用。如果你能提供更多的复制细节,我愿意再试一次:-)
这是名为 TargetLibrary.dll 的程序集中的唯一类型。我在自己的解决方案中编译它,并将程序集复制到 C:\Temp
.
public class HelperClass<T>
{
private int _someInt;
void SomeMethod(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());
}
}
}
}
运行 这会产生以下输出。
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>
我注意到某些类型的方法(例如泛型方法)中的字段或方法引用将是 FieldReference
类型,而不是 FieldDefinition
,尽管字段(或方法)在同一模块中,在同一类型中。我怎样才能从这个FieldReference
得到FieldDefinition
?
我尝试了 module.Import
和 module.MetadataResolver.Resolve
,但都不起作用。
跟进 this 问题,但更笼统。
编辑:
一个简单的通用类:
public class HelperClass<T>
{
private int _someInt;
void SomeMethod(int i)
{
_someInt = i;
}
}
SomeMethod
的正文包含:
...
IL_0008: ldarg.0
IL_0009: ldarg.1
IL_000a: stfdl System.Int32 HelperClass`1<T>::_someInt
....
IL_000a
操作码的操作数通常应该是 FieldDefinition
,毕竟它在同一个模块中。但是因为我想 HelperClass
是通用的,操作数是一个无法解析的 FieldReference
,我只能希望比较全名以实际找到 FieldDefinition
。
在这种情况下,这不是什么大问题,但是当引用是对其他泛型类型中的其他成员时,我相信有比枚举所有类型来查找更好的方法定义。
编辑:
HelperClass<>
来自 AssemblyDefinition.ReadAssembly
在运行时加载的模块,即 .Resolve()
returns null 而不是返回 FieldDefinition
.
更新:
事实证明,因为我正在更改通用类型中的字段名称,所以引用中断并且 Resolve()
返回 null。仍在为 this one.
更新:
我更改了代码以将类型分离到不同解决方案中的不同项目中。不幸的是,我仍然无法重现该问题,但如果有帮助,我愿意继续尝试。
我可以使用以下代码解析类型引用。如果你能提供更多的复制细节,我愿意再试一次:-)
这是名为 TargetLibrary.dll 的程序集中的唯一类型。我在自己的解决方案中编译它,并将程序集复制到 C:\Temp
.
public class HelperClass<T>
{
private int _someInt;
void SomeMethod(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());
}
}
}
}
运行 这会产生以下输出。
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>