6

我有一个使用此命令的自定义 msbuild 任务:

var workspace = Workspace.LoadStandAloneProject(csprojPath);

当我运行它时,它会引发以下错误:

  System.InvalidCastException 未被用户代码处理
  消息=无法将透明代理转换为类型“Roslyn.Utilities.SerializableDataStorage”。
  来源=Roslyn.Services
  堆栈跟踪:
       在 Roslyn.Utilities.RemoteServices.CreateInstance[T]()
       在 Roslyn.Services.Host.TemporaryStorageServiceFactory.CreateService(IWorkspaceServiceProvider workspaceServices)
       在 Roslyn.Services.Host.WorkspaceServiceProviderFactory.Provider.c__DisplayClass7.b__4()
       在 Roslyn.Utilities.NonReentrantLazy`1.get_Value()
       在 Roslyn.Services.Host.WorkspaceServiceProviderFactory.Provider.GetService[TWorkspaceService]()
       在 Roslyn.Services.SolutionServices..ctor(IWorkspaceServiceProvider 工作空间服务,ILanguageServiceProviderFactory 语言服务工厂)
       在 Roslyn.Services.Solution..ctor(SolutionId id,字符串文件路径,VersionStamp 版本,VersionStamp latestProjectVersion,ILanguageServiceProviderFactory languageServiceProviderFactory,IWorkspaceServiceProvider workspaceServices)
       在 Roslyn.Services.Host.SolutionFactoryServiceFactory.SolutionFactoryService.CreateSolution(SolutionId id)
       在 Roslyn.Services.Host.TrackingWorkspace.CreateNewSolution(ISolutionFactoryService solutionFactory,SolutionId id)
       在 Roslyn.Services.Host.TrackingWorkspace..ctor(IWorkspaceServiceProvider workspaceServiceProvider,布尔 enableBackgroundCompilation,布尔 enableInProgressSolutions)
       在 Roslyn.Services.Host.HostWorkspace..ctor(IWorkspaceServiceProvider workspaceServiceProvider,布尔 enableBackgroundCompilation,布尔 enableInProgressSolutions,布尔 enableFileTracking)
       在 Roslyn.Services.Host.LoadedWorkspace..ctor(ILanguageServiceProviderFactory languageServiceProviderFactory,IWorkspaceServiceProvider workspaceServiceProvider,IProjectFileService projectFileFactsService,IDictionary`2 globalProperties,布尔 enableBackgroundCompilation,布尔 enableFileTracking)
       在 Roslyn.Services.Host.LoadedWorkspace..ctor(ExportProvider exportProvider,布尔解决方案LoadOnly,布尔 enableFileTracking)
       在 Roslyn.Services.Host.LoadedWorkspace..ctor(布尔 enableFileTracking)
       在 Roslyn.Services.Host.LoadedWorkspace.LoadStandAloneProject(String projectFileName, String configuration, String platform, String language, Boolean enableFileTracking)
       在 Roslyn.Services.Workspace.LoadStandAloneProject(String projectFileName, String configuration, String platform, String language, Boolean enableFileTracking)
       ...

相同的代码在控制台应用程序中运行时,具有相同的项目,运行良好。

有任何想法吗?谷歌搜索没有帮助!

4

2 回答 2

4

这是 Roslyn 的示例 MsBuild 任务。

为了重建 Workspace.LoadProjectFromCommandLineArguments 方法所需的命令行,我们必须将 msbuild 文件中的一些信息传递到我们的任务中。

  • 引用的程序集:@(ReferencePath) 项组。
  • 要编译的 cs 文件:@(Compile) 项目组。
  • 基本目录:$(MSBuildProjectDirectory) 内置属性。

这就是 Roslyn 解析源文件所需的全部内容。(请参阅本文末尾的注释。)

所以创建一个 C# 类库项目。这些是您需要的项目参考:

Microsoft.Build.Framework
Microsoft.Build.Utilities.v4.0
Roslyn.Compilers
Roslyn.Services

自定义 MsBuild 任务的代码:

using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Roslyn.Services;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace RoslynMsBuildTask
{
    public class RoslynTask : Task
    {
        [Required]
        public ITaskItem[] ReferencePath { get; set; }

        [Required]
        public ITaskItem[] Compile { get; set; }

        [Required]
        public ITaskItem BaseDirectory { get; set; }

        public override bool Execute()
        {
            Log.LogMessage(MessageImportance.High, "RoslynTask.Execute called...\n");

            // Format the command line with the minimal info needed for Roslyn to create a workspace.
            var commandLineForProject = string.Format("/reference:{0} {1}",
                ReferencePath.Select(i => i.ItemSpec).ToSingleString(",", "\"", "\""),
                Compile.Select(i => i.ItemSpec).ToSingleString(" ", "\"", "\""));

            // Create the Roslyn workspace.
            var workspace = Workspace.LoadProjectFromCommandLineArguments("MyProject", "C#", commandLineForProject, BaseDirectory.ItemSpec);

            // Make sure that Roslyn actually parsed the project: dump the source from a syntax tree to the build log.
            Log.LogMessage(MessageImportance.High, workspace.CurrentSolution.Projects.First()
                .Documents.First(i => i.FilePath.EndsWith(".cs")).GetSyntaxRoot().GetText().ToString());

            return true;
        }
    }

    public static class IEnumerableExtension
    {
        public static string ToSingleString<T>(this IEnumerable<T> collection, string separator, string leftWrapper, string rightWrapper)
        {
            var stringBuilder = new StringBuilder();

            foreach (var item in collection)
            {
                if (stringBuilder.Length > 0)
                {
                    if (!string.IsNullOrEmpty(separator))
                        stringBuilder.Append(separator);
                }

                if (!string.IsNullOrEmpty(leftWrapper))
                    stringBuilder.Append(leftWrapper);

                stringBuilder.Append(item.ToString());

                if (!string.IsNullOrEmpty(rightWrapper))
                    stringBuilder.Append(rightWrapper);
            }

            return stringBuilder.ToString();
        }
    }
}

为了证明它确实有效,请在您的 csproj 文件末尾添加以下行(就在结束 Project 标记之前)。但前提是项目已经成功构建并且它可以在输出文件夹中找到您的任务 dll。

  <Target Name="AfterBuild" DependsOnTargets="RoslynTask"/>
  <UsingTask AssemblyFile="$(OutputPath)\RoslynMsBuildTask.dll" TaskName="RoslynMsBuildTask.RoslynTask" />
  <Target Name="RoslynTask">
    <RoslynTask ReferencePath="@(ReferencePath)" Compile="@(Compile)" BaseDirectory="$(MSBuildProjectDirectory)" />
  </Target>

它会将您的第一个 cs 文件的源转储到构建输出中。


请注意,其他 csc.exe 开关(如 ConditionalDirectives、输出类型等)也可能很重要,具体取决于您尝试执行的分析类型。您还可以使用此模式将它们传递给您的任务。有关 MsBuild 传递给 csc.exe 的属性的完整列表,请参阅 $(MSBuildToolsPath)\Microsoft.CSharp.targets 文件、CoreCompile 目标、Csc 任务。

于 2013-03-11T11:16:18.237 回答
-1

这是 MSBuild 的限制。Roslyn 无法在构建期间递归调用 MSBuild 以确定项目属性/文件/引用。为了IProject在构建任务期间创建 Roslyn,请尝试改用该LoadFromCommandLineArgs()方法。您需要构建您的任务以采用与 CscTask 最终传递给编译器相同的参数。

希望这可以帮助!

于 2013-01-21T17:11:25.503 回答