Roslyn将新方法添加到现有类

时间:2016-06-08 18:56:34

标签: c# roslyn visual-studio-extensions roslyn-code-analysis

我正在研究在Visual Studio扩展(VSIX)中使用Roslyn编译器,该扩展使用VisualStudioWorkspace来更新现有代码。在最近几天阅读了这篇文章,似乎有几种方法可以达到这个目标......我只是不确定哪种方法最适合我。

好的,我们假设用户在Visual Studio 2015中打开了他们的解决方案。他们点击我的扩展并(通过表单)他们告诉我他们想要将以下方法定义添加到界面:

GetSomeDataResponse GetSomeData(GetSomeDataRequest request);

他们还告诉我界面的名称,它是 ITheInterface

界面中已经包含一些代码:

namespace TheProjectName.Interfaces
{
    using System;
    public interface ITheInterface
    {
        /// <summary>
        ///    A lonely method.
        /// </summary>
        LonelyMethodResponse LonelyMethod(LonelyMethodRequest request);
    }
}

好的,我可以使用以下内容加载Interface Document:

Document myInterface = this.Workspace.CurrentSolution?.Projects?
    .FirstOrDefault(p 
        => p.Name.Equals("TheProjectName"))
    ?.Documents?
        .FirstOrDefault(d 
            => d.Name.Equals("ITheInterface.cs"));

那么,现在将新方法添加到现有接口的最佳方法是什么,理想情况下也可以写入XML注释(三重斜杠注释)?请记住,请求和响应类型(GetSomeDataRequest和GetSomeDataResponse)可能尚未存在。我对此非常陌生,所以如果你能提供代码示例,那就太棒了。

更新

我决定(可能)最好的方法是简单地注入一些文本,而不是尝试以编程方式构建方法声明。

我尝试了以下内容,但结果却出现了一个我不理解的例外情况:

SourceText sourceText = await myInterface.GetTextAsync();
string text = sourceText.ToString();
var sb = new StringBuilder();

// I want to all the text up to and including the last
// method, but without the closing "}" for the interface and the namespace
sb.Append(text.Substring(0, text.LastIndexOf("}", text.LastIndexOf("}") - 1)));

// Now add my method and close the interface and namespace.
sb.AppendLine("GetSomeDataResponse GetSomeData(GetSomeDataRequest request);");
sb.AppendLine("}");
sb.AppendLine("}");

检查这一点,这一切都很好(我的真实代码添加了格式和XML注释,但为了清楚起见删除了它。)

因此,知道这些是不可变的,我试图将其保存如下:

var updatedSourceText = SourceText.From(sb.ToString());
var newInterfaceDocument = myInterface.WithText(updatedSourceText);
var newProject = newInterfaceDocument.Project;
var newSolution = newProject.Solution;
this.Workspace.TryApplyChanges(newSolution);

但是这造成了以下异常:

bufferAdapter is not a VsTextDocData 
  

at Microsoft.VisualStudio.Editor.Implementation.VsEditorAdaptersFactoryService.GetAdapter(IVsTextBuffer bufferAdapter)     在Microsoft.VisualStudio.Editor.Implementation.VsEditorAdaptersFactoryService.GetDocumentBuffer(IVsTextBuffer bufferAdapter)     在Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.InvisibleEditor..ctor(IServiceProvider serviceProvider,String filePath,Boolean needsSave,Boolean needsUndoDisabled)     在Microsoft.VisualStudio.LanguageServices.RoslynVisualStudioWorkspace.OpenInvisibleEditor(IVisualStudioHostDocument hostDocument)     在Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.DocumentProvider.StandardTextDocument.UpdateText(SourceText newText)     在Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.VisualStudioWorkspaceImpl.ApplyDocumentTextChanged(DocumentId documentId,SourceText newText)     在Microsoft.CodeAnalysis.Workspace.ApplyProjectChanges(ProjectChanges projectChanges)     在Microsoft.CodeAnalysis.Workspace.TryApplyChanges(解决方案newSolution)     在Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.VisualStudioWorkspaceImpl.TryApplyChanges(Solution newSolution)

1 个答案:

答案 0 :(得分:3)

如果我是你,我会利用所有Roslyn的好处,即我会使用SyntaxTree的{​​{1}}而不是处理文件文本(你可以不使用总是罗斯林。

例如:

Document

请注意,这是非常原始的代码,Roslyn API在分析/处理语法树,获取符号信息/引用等方面非常强大。我建议您查看此page和此page以供参考。