8

我刚刚发现了 NRefactory 5,我猜它是最适合我当前问题的解决方案。目前我正在开发一个小的 C# 脚本应用程序,我想为其提供代码完成。直到最近,我还是使用 Microsoft 的“Roslyn”项目完成了这项工作。但由于该项目的最新更新需要 .Net Framework 4.5,我不能再使用它,因为我希望该应用程序也可以在 Win XP 下运行。所以我必须在这里切换到另一种技术。

我的问题不是编译的东西。.Net CodeDomProvider 也可以通过更多的努力来做到这一点。问题在于代码完成的东西。据我所知,NRefactory 5 提供了提供代码完成所需的一切(解析器、类型系统等),但我就是不知道如何使用它。我查看了 SharpDevelop 源代码,但他们没有使用 NRefactory 5 来完成代码,他们只使用它作为反编译器。因为我也找不到如何在网络中使用它来完成代码的示例,所以我想我可能会在这里找到一些帮助。

情况如下。我有一个包含脚本代码的文件。实际上,它甚至不是文件,而是我从编辑器控件获得的字符串(顺便说一句:我为此使用 AvalonEdit。很棒的编辑器!)和一些需要引用的程序集。因此,没有解决方案文件,没有项目文件等,只有一串源代码和程序集。

我查看了 NRefactory 5 附带的 Demo 和关于代码项目的文章,并得到了这样的内容:

var unresolvedTypeSystem = syntaxTree.ToTypeSystem();

IProjectContent pc = new CSharpProjectContent();

// Add parsed files to the type system
pc = pc.AddOrUpdateFiles(unresolvedTypeSystem);

// Add referenced assemblies:
pc = pc.AddAssemblyReferences(new CecilLoader().LoadAssemblyFile(
    System.Reflection.Assembly.GetAssembly(typeof(Object)).Location));

我的问题是我不知道如何继续。我什至不确定这是否是实现我目标的正确方法。如何使用CSharpCompletionEngine?还需要什么?等等。您看到目前有很多事情还不清楚,我希望您能对此有所了解。

提前非常感谢大家!

4

3 回答 3

7

我刚刚编译了一个使用 AvalonEdit 和 NRefactory 完成 C# 代码的示例项目。

它可以在 Github 上找到。

于 2013-02-21T17:00:56.213 回答
3

看看方法ICSharpCode.NRefactory.CSharp.CodeCompletion.CreateEngine。您需要创建一个实例CSharpCompletionEngine并传入正确的文档和解析器。我设法让它适用于 CTRL+Space compltition 场景。但是,我在引用其他命名空间中的类型时遇到了麻烦。看起来CSharpTypeResolveContext没有考虑使用命名空间语句 - 如果我用 解析引用CSharpAstResolver,它们就可以解析,但我无法在代码完成场景中正确使用这个解析器......

更新#1:

我刚刚通过从未解决的失败中获取解析器来设法完成工作。

这是片段:

var mb = new DefaultCompletionContextProvider(doc, unresolvedFile);
var resolver3 = unresolvedFile.GetResolver(cmp, loc); // get the resolver from unresolvedFile
var engine = new CSharpCompletionEngine(doc, mb, new CodeCompletionBugTests.TestFactory(resolver3), pctx, resolver3.CurrentTypeResolveContext );

更新#2:

这是完整的方法。它引用单元测试项目中的类,所以您需要将它们引用/复制到您的项目中:

public static IEnumerable<ICompletionData> DoCodeComplete(string editorText, int offset) // not the best way to put in the whole string every time
{

  var doc = new ReadOnlyDocument(editorText);
  var location = doc.GetLocation(offset);

  string parsedText = editorText; // TODO: Why there are different values in test cases?


  var syntaxTree = new CSharpParser().Parse(parsedText, "program.cs");
  syntaxTree.Freeze();
  var unresolvedFile = syntaxTree.ToTypeSystem();

  var mb = new DefaultCompletionContextProvider(doc, unresolvedFile);

  IProjectContent pctx = new CSharpProjectContent();
  var refs = new List<IUnresolvedAssembly> { mscorlib.Value, systemCore.Value, systemAssembly.Value}; 
  pctx = pctx.AddAssemblyReferences(refs);
  pctx = pctx.AddOrUpdateFiles(unresolvedFile);

  var cmp = pctx.CreateCompilation();

  var resolver3 = unresolvedFile.GetResolver(cmp, location);
  var engine = new CSharpCompletionEngine(doc, mb, new CodeCompletionBugTests.TestFactory(resolver3), pctx, resolver3.CurrentTypeResolveContext );


  engine.EolMarker = Environment.NewLine;
  engine.FormattingPolicy = FormattingOptionsFactory.CreateMono();

  var data = engine.GetCompletionData(offset, controlSpace: false);
  return data;

}

}

希望它有帮助,马特拉

于 2012-10-02T19:35:26.440 回答
2

NRefactory 5 is being used in SharpDevelop 5. The source code for SharpDevelop 5 is currently available in the newNR branch on github. I would take a look at the CSharpCompletionBinding class which has code to display a completion list window using information from NRefactory's CSharpCompletionEngine.

于 2012-09-20T19:01:57.467 回答