簡體   English   中英

Visual Studio 中未加載源生成器依賴項

[英]Source Generators dependencies not loaded in Visual Studio

我正在研究源代碼生成器,但我遇到了依賴問題:

It will not contribute to the output and compilation errors may occur as a result. Exception was of type 'FileNotFoundException' with message 'Could not load file or assembly 'Flurl.Http, Version=3.0.1.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.'

有很多關於如何將依賴項打包到 nuget 的信息,但我直接引用分析器項目是這樣的:

<ProjectReference Include="SG.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />

在分析器項目中,我添加了<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>並且所有依賴項都在 output 目錄中可用,但是 VS 沒有使用該目錄 - 它使用AppData\Local\Temp\VBCSCompiler\AnalyzerAssemblyLoader\[...]那里只復制一個 DLL。

可以做些什么來完成這項工作?

應該工作的方式在source-generators cook-book中進行了概述,他們的例子是:

<Project>
  <PropertyGroup>
    <GeneratePackageOnBuild>true</GeneratePackageOnBuild> <!-- Generates a package at build -->
    <IncludeBuildOutput>false</IncludeBuildOutput> <!-- Do not include the generator as a lib dependency -->
  </PropertyGroup>

  <ItemGroup>
    <!-- Take a private dependency on Newtonsoft.Json (PrivateAssets=all) Consumers of this generator will not reference it.
         Set GeneratePathProperty=true so we can reference the binaries via the PKGNewtonsoft_Json property -->
    <PackageReference Include="Newtonsoft.Json" Version="12.0.1" PrivateAssets="all" GeneratePathProperty="true" />

    <!-- Package the generator in the analyzer directory of the nuget package -->
    <None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />

    <!-- Package the Newtonsoft.Json dependency alongside the generator assembly -->
    <None Include="$(PkgNewtonsoft_Json)\lib\netstandard2.0\*.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
  </ItemGroup>
</Project>

但是,根據我的經驗,這仍然不可靠或不可靠; 這是公認的,我的印象是改善這種體驗是未來計划的一部分,但是:老實說,現在最好不要使用核心框架和已經加載的 Roslyn 庫之外的依賴項。 如果您的依賴項與分析器/生成器位於同一存儲庫中,您可能可以在構建期間簡單地吸收代碼, 例如從這里

<ItemGroup>
    <!-- compile what we need from protobuf-net directly; package refs cause pure pain in anaylizers-->
    <Compile Include="../protobuf-net.Core/**/*.cs" Link="protobuf-net.Core"/>
    <Compile Remove="../protobuf-net.Core/obj/**/*.cs" />
    <Compile Include="../protobuf-net.Reflection/**/*.cs"  Link="protobuf-net.Reflection"/>
    <Compile Remove="../protobuf-net.Reflection/obj/**/*.cs" />
</ItemGroup>

我找到了通過一些技巧使其或多或少可靠地工作的方法。

在此之前我也嘗試過 ILMerge,但它不起作用(缺少方法異常)。

解決方案:

首先,我將依賴項嵌入到源生成器程序集中,如下所示:

<ItemGroup>
    <PackageReference Include="Newtonsoft.Json" Version="13.0.1" GeneratePathProperty="true" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
    <EmbeddedResource Include="$(PKGNewtonsoft_Json)\lib\netstandard2.0\Newtonsoft.Json.dll" Visible="false" />
</ItemGroup>

然后我為AppDomain (生成器類中的靜態構造函數)創建了AssemblyResolve處理程序,如下所示:

AppDomain.CurrentDomain.AssemblyResolve += (_, args) =>
{
    AssemblyName name = new(args.Name);
    Assembly loadedAssembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetName().FullName == name.FullName);
    if (loadedAssembly != null)
    {
        return loadedAssembly;
    }

    string resourceName = $"Namespace.{name.Name}.dll";

    using Stream resourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
    if (resourceStream == null)
    {
        return null;
    }
    
    using MemoryStream memoryStream = new MemoryStream();
    resourceStream.CopyTo(memoryStream);

    return Assembly.Load(memoryStream.ToArray());
};

現在有一個明確的答案。 Source Generator Samples包含一個示例.csproj ,它具有所需的設置。

我用它用Sprache制作了一個源代碼生成器,效果很好。

在此處粘貼示例.csproj以供參考:

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <LangVersion>8.0</LangVersion>
</PropertyGroup>

<ItemGroup>
    <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="$(MicrosoftNetCompilersToolsetVersion)" PrivateAssets="all" />
    <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.0.0" PrivateAssets="all" />
</ItemGroup>

<ItemGroup>
    <!-- Generator dependencies -->
    <PackageReference Include="CsvTextFieldParser" Version="1.2.2-preview" GeneratePathProperty="true" PrivateAssets="all" />
    <PackageReference Include="Handlebars.Net" Version="1.10.1" GeneratePathProperty="true" PrivateAssets="all" />
    <PackageReference Include="Newtonsoft.Json" Version="12.0.1" GeneratePathProperty="true" PrivateAssets="all" />
</ItemGroup>

<PropertyGroup>
    <GetTargetPathDependsOn>$(GetTargetPathDependsOn)</GetTargetPathDependsOn>;GetDependencyTargetPaths
</PropertyGroup>

<Target Name="GetDependencyTargetPaths">
    <ItemGroup>
      <TargetPathWithTargetPlatformMoniker Include="$(PKGCsvTextFieldParser)\lib\netstandard2.0\CsvTextFieldParser.dll" IncludeRuntimeDependency="false" />
      <TargetPathWithTargetPlatformMoniker Include="$(PKGHandlebars_Net)\lib\netstandard2.0\Handlebars.dll" IncludeRuntimeDependency="false" />
      <TargetPathWithTargetPlatformMoniker Include="$(PKGNewtonsoft_Json)\lib\netstandard2.0\Newtonsoft.Json.dll" IncludeRuntimeDependency="false" />
    </ItemGroup>
</Target>
</Project>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM