C#反射并找到所有引用

时间:2011-03-30 17:44:32

标签: c# reflection reference reflector

鉴于DLL文件,我希望能够找到该DLL文件中所有方法的调用。我怎么能这样做?

基本上,我如何以编程方式执行Visual Studio已经执行的操作?

我不想使用像.NET Reflector之类的工具来做这件事,但反思很好,可能也是必要的。

6 个答案:

答案 0 :(得分:48)

要找出使用方法MyClass.Foo()的位置,您必须分析所有包含对包含MyClass的程序集的引用的程序集的所有类。我写了一个关于代码如何看起来的简单概念证明。在我的例子中,我使用了由Jb Evain编写的this library(它只是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参数,并且它不处理泛型参数。我确信忘记了其他细节。它只是表明它可以完成。

答案 1 :(得分:3)

单独的反射不足以找到给定程序集中对方法的所有引用。 Reflection为您提供了任何特定方法(MethodInfo.GetMethodBody.GetILAsByteArray)的主体的字节数组,您必须自己解析它以获取对其他方法的引用。有几个公开的“CIL读者”图书馆(我没有使用它们 - 希望有人会发布更多内容)。

添加FxCop选项 - 根据您的场景,您可以重用FxCop提供的CIL解析逻辑(Visual Studio代码分析)并添加您的自定义规则,如果在代码分析中运行它是可以的你。

答案 2 :(得分:2)

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

答案 3 :(得分:1)

我会考虑反映Visual Studio程序集,看看你是否可以在逆向工程代码库中找到它。我相信VS实际上是在导航代码而不是反映。正如迈克尔发布的那样,反思非常适合确定装配的位,而不是那些位的消费者。然而,我没有重新审视反思来证实我的怀疑。

答案 4 :(得分:0)

嘿,这是一个示例,假设您要搜索当前程序集中的所有调用。我编写了这个尝试获取参数值,以便为具有一些默认值的方法设置一些约束。但是我无法获得参数值,我只获得了类型和默认值。

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.
}

希望它有所帮助。

答案 5 :(得分:-1)

请参阅Stack Overflow问题 Get a list of functions for a DLL

从上面撕掉(感谢Jon Skeet):

  

对于特定的程序集,可以使用Assembly.GetTypes来获取类型,然后为每个类型调用Type.GetMethods(),Type.GetProperties()等,或者只使用Type.GetMembers()。

     

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

     

您可能还想查看Managed Extensibility Framework,它可以更轻松地实现扩展系统。