在C#中查找已编译类的源文件

3
我希望能找到已编译的.NET程序集中特定类的相关源文件。例如:
MyAsm.Namespace.Foo  -> C:\Source\foo.cs
MyAsm.Namespace.Bar  -> C:\Source\Code\MoreCode\Common.cs
MyAsm.Namespace2.Bar -> C:\Source\Code\MoreCode\Common.cs
...

我使用标准的System.Reflection功能进行程序集反射/提取感兴趣的类型信息。现在,我需要找到类的源.cs文件。虽然我已经有了一个暴力解决方案作为临时解决办法,但它速度太慢,无法接受。我希望整个过程能在约5秒钟内完成。目前,反射提取部分不到1秒钟,"文件关联"需要几分钟。我认为在4秒钟内扫描几MB并不是不合理的要求。不幸的是,有几个注意事项阻碍了快捷方式。1.我不知道文件的名称,因此每次运行都需要执行dir / s *.cs来枚举所有潜在的源文件。2.类名不总是匹配源文件,它可以提示可能的位置,但不保证有效。3.某些情况下,在同一文件中定义多个类。4.大约有20k .cs文件/63MB的源文件。5.我需要将~10k的类与它们的文件关联起来。6.我不想逐步构建具有其中声明的类名/文件名的数据库,因为文件内容会更改,并且我将需要维护这个数据库等问题(尽管如果其他方法失败,我可能必须采用这种方法)。7.操作系统上将运行的程序将不会启用Windows搜索/索引,因此也无法使用该方法。
我已经尝试了以下方法:
1.使用findstr.exe-速度太慢。 2.创建一个.net应用程序,将所有文件加载到内存中-太慢以至于找不到*.cs /加载所有文件,一旦它们在内存中就可以快速扫描文件。 3.从所有较小的文件中创建一个大型源文件,加载它,扫描等-同样太慢。构建文件需要几分钟,一旦加载就很快。 4.读取PDB文件-我正在调查PDB2XML.exe,虽然它确实输出文件名,并且运行速度很快,但我看不到如何将类与文件名关联起来。
那么,有没有其他建议、魔术或关于PDB2XML的经验呢?

2
如果系统上没有原始源文件怎么办? - Ben Finkel
一个非常简单的事情是在文件中搜索类名,例如查找所有包含class\s+<ClassName>的文件。 - Mohamed Nuur
@BenFinkel,是的,他们就是。这是我能保证的一件事。 - jasper
1
@MohamedNuur 这是我“尝试过的事情”清单上的第二项,加载所有这些文件需要太长时间了。 - jasper
4个回答

2

这并不能完全解决你所面临的问题,因为你想获取任意类的文件路径,但这对我的用途很容易实现,我只需要从源位置获取指向某个文件的指针。我在单元测试中使用这个方法,因此性能并不是非常重要。

var x = new StackTrace(true);
var file = x.GetFrame(0).GetFileName();

我应该在问题中说清楚,但我需要在编译时或编译后解决问题,而不是在运行时。Simon的答案正是我所需要的。 - jasper
哦,我不认为这个解决方案很好地解决了你的特定问题,但我把它放在这里,因为它不值得一个全新的问题,并且我想分享这些信息。 - Arrya Regan

2

如果你能够编辑源代码,你可以使用反射和System.Runtime.CompilerServices.CallerFilePath来实现。只需将属性添加到每个文件的源代码中即可。对于部分类,可能需要想出一些巧妙的办法。

这个示例提供了放置属性的源文件和行号。


Translated:
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = false)]
public sealed class SourceInfoAttribute : Attribute
{
    public SourceInfoAttribute([CallerLineNumber]int sourceLineNumber = 0, [CallerFilePath] string sourceFilePath = "")
    {
        SourceLineNumber = sourceLineNumber;
        SourceFilePath = sourceFilePath;
    }

    internal int SourceLineNumber { get; set; }
    internal string SourceFilePath { get; set; }
}    

1

在磁盘上使用PDB文件是我认为最好的选择。文件名(由ISymbolDocument.URL表示)与序列点相关。序列点与方法(包括属性get/set)相关,而不是类。当然,.NET类源代码可以存储在多个文件中。因此,您需要浏览类型的所有成员(例如使用反射),以确定所有相应的文件。


这正是我正在寻找的。不过,GetSequencePoints 并非每个方法都返回输出。据我所见,自动属性也是如此。这很有道理,因为调试器不会逐步执行它们。有什么办法可以将它们联系起来吗? - jasper
编译器不会为自动属性生成任何符号,正如您所发现的那样,因此如果类仅包含这些属性,则无法确定其源文件。但这应该是非常罕见的情况。 - Simon Mourier

0

我不知道在.NET中文件名和程序集名称之间是否存在任何关系,实际上一个文件中可以定义多个程序集,因此我不明白如何在不物理查看每个源代码文件并搜索类定义或维护运行索引的情况下完成此操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接