我在你问这个问题的同一天开始探索 NRefactory)所以,我不能称自己为 NRefactory 专家。但我可以告诉你方法,我如何使用它。
理论资料: http: //www.codeproject.com/Articles/408663/Using-NRefactory-for-analyzing-Csharp-code
首先,您可以使用此示例项目中的 Visual Studio 解决方案模型为您的 IDE 解决方案格式制作类似的类:https ://github.com/icharpcode/NRefactory/tree/master/ICSharpCode.NRefactory.ConsistencyCheck
共有三个类你需要:CSharpFile、CSharpProject和Solution。请看它的源代码,你就会知道,NRefactory 是如何对代码文件进行语法分析的。注意 CSharpProject 的“ Compilation ”字段和 CSharpFile 的“ CreateResolver ”方法。
其次,您需要对代码进行语义分析。为此,您需要实施
ICSharpCode.NRefactory.CSharp.Resolver.IResolveVisitorNavigator
界面。但在您的情况下,您最好使用现有的 NRefactory 实现:
ICSharpCode.NRefactory.CSharp.Resolver.FindReferencedEntities
具有两个参数的构造函数等待两个处理程序。首先执行然后解析的语法元素是类型的引用,包含在您的解决方案或引用的程序集中(如变量声明)。当解析的语法元素是某个类型的成员的引用时,第二个被执行(例如,“(new object()).ToString()”作为“object”实例的成员“ToString”的引用)。两个处理程序的第一个参数是 AstNode:未解析的代码语法元素。第二个参数是对应的解析语义元素:第一个处理程序的 IType 和另一个处理程序的 IMember。因此,您需要使用处理程序创建导航器实例,例如,将语法和相应的语义元素保存在字典中。
您的代码可能如下所示:
var solution = new Solution(slnPath);
IDictionary<AstNode, IType> typesMap = new Dictionary<AstNode, IType>();
IDictionary<AstNode, IMember> membersMap = new Dictionary<AstNode, IMember>();
var navigator = new FindReferencedEntities(typesMap.Add, membersMap.Add);
foreach (var codeFile in solution.AllFiles)
{
codeFile.CreateResolver().ApplyNavigator(navigator);
}
执行此代码字典后,typeMap和membersMap将包含代码的语法元素,NRefactory 能够在字典的键中解析,以及在值中对应的解析语义。如果您编写自动完成,则在使用时处理的代码很可能无法编译(因为用户此时编写它)。因此,您的应用程序不仅必须使用已解析的代码,而且还必须使用未解析的代码。要获取代码文件中未解析的语法元素,此时用户编辑,您必须使用:
var syntaxTree = solution.Projects
.Where(p => p.Title.Equals(editableProjName))
.Files
.Where(f => f.FileName.Equals(editableFileNamePath))
.SyntaxTree;
SyntaxTree 是一个“ ICSharpCode.NRefactory.CSharp.SyntaxTree ”,它继承了 AstNode 类。它是代码文件的根语法节点。变量syntaxTree将包含当前正在编辑的文件的所有未解析的语法元素。要遍历语法树,您可以使用 AstNode 可枚举成员,如 Descendants、Children、GetParent() 等。或者您可以使用“Visitor”模式和 AstNode 方法“AcceptVisitor”。
在为自动完成生成列表时,您可以使用 typesMap 和 membersMap 作为已声明类型及其成员的快速存储,如果未找到用户输入,则可以使用 syntaxTree 作为慢速存储。
NRefactory 是一个非常广泛的话题,我无法完全揭示它。很遗憾,这个强大的框架没有详细的文档。但是希望我的回答可以帮助到你。