2011-03-30 40 views
33

给定一个DLL文件,我希望能够找到该DLL文件中的方法的所有调用。我怎样才能做到这一点?C#反射和查找所有引用

从本质上讲,我怎样才能以编程方式做Visual Studio已经做了什么?

我不想使用像.NET Reflector这样的工具来做到这一点,但反射很好,可能是必要的。

+2

您是否需要检测对该方法的静态调用?应该用反射和反射发射来检测电话吗? – 2011-03-30 17:48:02

+0

而且应该使用非托管代码吗?并非所有的DLL都支持反射。 – 2011-03-30 17:50:24

+1

@Darin:那些会锦上添花,但没有必要。 @James:我不认为我必须担心非托管代码。我怎么能在不支持反射的dll上做到这一点? – user420667 2011-03-30 18:18:34

回答

43

要找出使用方法MyClass.Foo()的位置,必须分析所有包含MyClass的程序集引用的所有程序集的类。我写了一个关于这个代码的外观的简单证明。在我的例子中,我使用this library写的JB Evain(这只是a single .cs file):

我写了一个小测试类来分析:

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参数,也没有处理泛型参数。我相信,也忘记了其他细节。它只是表明它可以完成。

+0

不错。这也使用Linq作为select语句。有时间构建一些依赖关系图。 – user420667 2011-03-30 20:47:41

+0

我收到此错误消息:“价值不符合预期范围。”从这段代码:'this.body = method.GetMethodBody();如果(this.body == null)抛出新的ArgumentException();'我想知道如何有无身体的方法(或者还有什么可以进行)。有什么想法吗? – ekkis 2013-09-14 00:22:39

+1

@ekkis:(抽象类的)抽象方法是没有身材的。您可以通过检查“MethodBase.IsAbstract”来检查方法是否抽象。 – 2013-09-14 01:00:23

-1

请参阅堆栈溢出问题Get a list of functions for a DLL

从上面的(感谢乔恩斯基特)受骗:

对于特定的组件,您可以使用Assembly.GetTypes拿到类型,然后为每个呼叫类型Type.GetMethods(),Type.GetProperties ()等,或者只是Type.GetMembers()。

但是,对于插件功能来说,拥有插件必须实现的通用接口通常是一个好主意 - 这可以减少您需要使用的反射量。使用Type.IsAssignableFrom()检查某个类型是否与特定接口兼容。

您可能还想看看托管扩展性框架,它可以使实现扩展系统更容易。

+2

我不明白这个答案如何帮助找到给定方法的调用。它有助于列出目标程序集中的类型,方法,属性等,但OP正在寻找一种方法来检测给定方法是否调用另一个方法。 – 2011-03-30 17:51:10

+0

这不是OP询问的问题。 – 2011-03-30 17:52:38

+0

这不是OP正在寻找的东西。这列出了方法,但没有列出它们的调用。 – jason 2011-03-30 17:52:41

1

我会考虑反映Visual Studio程序集,看看你是否可以在逆向工程代码库中找到它。我相信VS实际上是在浏览代码而不是反思。正如Michael所发布的,反射对于确定组件的位数非常重要,但不是那些位的消费者。但是,我没有重新审视反思来确认我的怀疑。

2

您可以查看MSDN杂志文章Determining .NET Assembly and Method References

+0

+1:请注意,你将不得不搜索一些IL阅读器 - 反射器的一个不是直接可用,据我所知... – 2011-03-30 18:00:50

+0

好文章。但它建议使用Reflector作为方法依赖关系。我想他们都归结为解析IL。 – user420667 2011-03-30 20:46:43

3

单靠反射并不足以找到给定装配中的方法的所有引用。反射为任何特定方法的主体提供了一个字节数组(MethodInfo.GetMethodBody.GetILAsByteArray),您必须自己解析它以引用其他方法。有几个公开可用的“CIL阅读器”库(我没有使用它们 - 希望有人会发布更多)。

添加FxCop选项 - 根据您的场景,您可以重复使用由FxCop(Visual Studio代码分析)提供的CIL分析逻辑,并添加自定义规则(如果作为代码分析的一部分运行它)对您而言可以。