给定一个DLL文件,我想能够找到该DLL文件中所有对某个方法的调用。我应该如何做?
实质上,我应该如何以编程方式执行Visual Studio已经完成的操作?
我不想使用类似.NET Reflector这样的工具来完成此操作,但反射是可以的,也可能是必要的。
实质上,我应该如何以编程方式执行Visual Studio已经完成的操作?
我不想使用类似.NET Reflector这样的工具来完成此操作,但反射是可以的,也可能是必要的。
MyClass.Foo()
的位置,您需要分析所有对包含MyClass
的程序集有引用的所有类。我编写了一个简单的概念验证代码来说明这个过程。在我的示例中,我使用这个库(它只是由Jb Evain编写的一个单独的.cs文件):public class TestClass
{
public void Test()
{
Console.WriteLine("Test");
Console.Write(10);
DateTime date = DateTime.Now;
Console.WriteLine(date);
}
}
我写了这段代码来打印出在TestClass.Test()
中使用的所有方法:
MethodBase methodBase = typeof(TestClass).GetMethod("Test");
var instructions = MethodBodyReader.GetInstructions(methodBase);
foreach (Instruction instruction in instructions)
{
MethodInfo methodInfo = instruction.Operand as MethodInfo;
if(methodInfo != null)
{
Type type = methodInfo.DeclaringType;
ParameterInfo[] parameters = methodInfo.GetParameters();
Console.WriteLine("{0}.{1}({2});",
type.FullName,
methodInfo.Name,
String.Join(", ", parameters.Select(p => p.ParameterType.FullName + " " + p.Name).ToArray())
);
}
}
它给了我以下输出:
System.Console.WriteLine(System.String value);
System.Console.Write(System.Int32 value);
System.DateTime.get_Now();
System.Console.WriteLine(System.Object value);
这个例子显然远远没有完善,因为它不处理ref和out参数,也不处理泛型参数。我相信还忘记了其他细节。它只是表明可以完成。
this.body = method.GetMethodBody(); if (this.body == null) throw new ArgumentException();
我想知道可能是如何出现没有方法体(或其他可能的情况)。你有什么想法吗? - ekkisMethodBase.IsAbstract
来检查该方法是否为抽象方法。 - Elian EbbingSystem.GetType()
- 我不确定这个方法有什么特殊之处,但是 .GetMethodBody()
也为空。我想知道在这些情况下我们应该抛出 ArgumentException 还是只是默默地失败。 - ekkis[MethodImpl(MethodImplOptions.InternalCall)]
属性,并在 CL 运行时本身中实现。我认为你是对的,如果出现这种情况,GetInstructions()
方法应该返回一个空列表而不是异常。 - Elian EbbingMethodBodyReader
çڑ„و–¹و،ˆوک¯ن½؟用NuGetهŒ…mono.reflection,ه¹¶ن½؟用var instructions = Disassembler.GetInstructions(methodBase)
و¥èژ·هڈ–وŒ‡ن»¤م€‚ - Joep Geevers嘿,这是一个假设您想在当前程序集中搜索所有调用的示例。我编写了这个代码,试图获取参数值以便为具有某些默认值的方法设置一些约束条件。但是我无法成功获取参数值,只得到了类型和默认值。
var currentAssembly = Assembly.GetExecutingAssembly();
foreach (var method in currentAssembly.GetTypes().Where(type => type.IsClass)
.SelectMany(cl => cl.GetMethods())
.OfType<MethodBase>()
.SelectMany(mb => mb.GetInstructions())
.Select(inst => inst.Operand).OfType<MethodInfo>()
.Where(mi => mi.Name == "<YourMethodName>"))
{
//here are your calls.
}
请参考 Stack Overflow 上的问题Get a list of functions for a DLL。
从上面提取的内容(感谢 Jon Skeet):
对于特定的程序集,您可以使用 Assembly.GetTypes 获取类型,然后对于每个类型调用 Type.GetMethods()、Type.GetProperties() 等,或者只是 Type.GetMembers()。
但是,对于插件功能,通常最好有一个公共接口,插件必须实现该接口 - 这减少了需要使用的反射量。使用 Type.IsAssignableFrom() 检查类型是否与特定接口兼容。
您还可以查看托管可扩展性框架,它可以使实现扩展系统更加容易。