CS0012 - 您必须添加对程序集“X Version=N”的引用 - 编译器如何确定“X”和“N”应该是什么?

问题描述 投票:0回答:1

CS0012 有很多的答案。这个问题很具体,如果有答案,我找不到它。

我编写了一个包,称之为:

MyReservedName.Portable.SomePackage
。它的装配定义了
public class TypeA

在我的 WinForms 应用程序中,有 .csproj 文件引用最新的稳定包版本 1.0.7(不是 1.0.6):

<ItemGroup>
    <PackageReference Include="MyReservedName.Portable.SomePackage" Version="1.0.7" />
</ItemGroup>

这不是第三方黑匣子。我在我自己的库上遇到此错误

Error CS0012 The type 'TypeA' is defined in an assembly that is not referenced. You must add a reference to assembly 'MyReservedName.Portable.SomePackage, Version=1.0.6.0, Culture=neutral, PublicKeyToken=ef60c83b99c9b20e'.


我可以告诉你的是

TypeA

 
是在 1.0.7 中定义的并且 任何地方都没有 1.0.6 版本

1.0.6 不在 int.nugettest.org、nugettest.org 或任何本地 NuGet 源上。
  • 我已经清除了 nuget 缓存。反复。
  • 我没有提到 1.0.6 版本。哪里都没有。
  • NuGet 包管理器仅显示 1.0.7。例如,没有降级选项到 1.0.6 版本。
  • 甚至像过去“抓住”我的流氓 Nuget.config 文件之类的东西也已被彻底搜索。
所以我的问题很简单。我什至不要求修复错误本身。但是
编译器从哪里想到

TypeA将在这个特定的不存在的版本1.0.6中得到解决?看起来像是从帽子里拿出来的,但我知道它是从某个地方获取这个值的......

我想第二个问题是为什么它会避开 1.0.7 程序集中免费提供的 

TypeA



我的图书馆已签名。这会不会有什么关系呢?当我升级版本或其他任何内容时,我不需要更改

<AssemblyOriginatorKeyFile>,对吧?




c# winforms nuget
1个回答
0
投票

对我来说,错误消息毫无意义,本质上是:

我找不到
    AssemblyA
  • (因此它不可能反映它的类型)
    但是,如果我
  • 能够
  • 找到AssemblyA(我不能),我知道它会包含
    TypeA
    (因为显然我拥有魔法能力)。
    
    
  • 所以问题是
它怎么知道?

显然它可以访问包含 PublicKeyToken 的元数据(

nuspec
文件没有)。它以其他方式进行“反向查找”链接。
可能无法知道编译器启发式是什么。因此决定自己尝试一下,以确定普通人是否可以检查 NuGet 缓存:

%userprofile%.nuget\packages

并抓取足够的元数据,以消除构建中出现的问题中的试验结束错误。

经过一周的头撞墙后,我很高兴地报告,该策略确实生成了下面的日志,揭示了类型如何链接到“丢失的”程序集

并且

显示了确切地出了什么问题无需猜测。


类型到程序集的反向查找

NuGet 缓存中的所有 dll 文件都可以加载并反映类型名称。可能存在重复的程序集,并且无法卸载它们,因此这需要在单独的进程中完成。对于单个 dll,我们将制作此控制台应用程序实用程序

reflect-single-asm.exe

,它将 dll 路径作为命令行参数:

using System.Reflection;

string asmPath = args[0];
try
{
    Assembly asm = Assembly.LoadFrom(asmPath);

    Console.WriteLine();
    Console.WriteLine($"NuGet Asm Path: {asmPath}");
    Console.WriteLine($"NuGet Asm Meta: {asm.FullName}");
    foreach (Type type in asm.GetTypes())
    {        
        Console.WriteLine($"Type: {type.AssemblyQualifiedName}");
    }
}
catch (Exception ex)
{
    Console.WriteLine($"Error: {ex.Message}");
}

现在,顶级控制台应用程序会迭代 NuGet 缓存中的包,并以可调试的方式准确显示正在发生的情况:

using System.Diagnostics; string nugetPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".nuget", "packages"); if(Directory.Exists(nugetPath)) { // Filter down the info to what I care about at the moment. var filter = new[] { "Portable.Disposable", "Error" }; Debug.WriteLine(DateTime.Now); foreach (var directory in Directory.GetDirectories(nugetPath).Where(_=>_.Contains("IVSoftware", StringComparison.OrdinalIgnoreCase))) { foreach (var dllPath in Directory.GetFiles(directory, "*.dll", SearchOption.AllDirectories)) { var exePath = Path.Combine( AppDomain.CurrentDomain.BaseDirectory, "Util", "net7.0", "reflect-single-asm.exe"); ProcessStartInfo startInfo = new ProcessStartInfo(exePath, dllPath) { UseShellExecute = false, RedirectStandardOutput = true, CreateNoWindow = true, }; Process process = Process.Start(startInfo); string[] output = process .StandardOutput .ReadToEnd() .Split('\n').Select(_=>_.Trim()) .ToArray(); if( (output.FirstOrDefault(_=>_.Contains("NuGet Asm Path")) is string header) && output.Any(_=>_.Contains("Disposable", StringComparison.OrdinalIgnoreCase)) ) { bool viewAll = output.Any(_ => _.Contains("Could not load", StringComparison.OrdinalIgnoreCase)); for (int i = 0;i<output.Length;i++) { var line = output[i]; switch (i) { case 0: case 1: case 2: Debug.WriteLine(line); break; default: if(viewAll || filter.Any(_=>line.Contains(_, StringComparison.OrdinalIgnoreCase))) { Debug.WriteLine(line); } break; } } } else { break; } } } }

1[2]中,我们看到可以在哪里进行反向查找:

    IVSoftware.Portable.Disposable, Version=1.0.6.0, Culture=neutral, PublicKeyToken=ef60c83b99c9b20e
  • 在缓存中
    特定类型,例如
  • IVisibleIndex
  • 通过元数据条目链接到提供者:
    IVSoftware.Portable.Disposable.IVisibleIndex, IVSoftware.Portable.Disposable, Version=1.0.6.0, Culture=neutral, PublicKeyToken=ef60c83b99c9b20e
    并且有问题的 dll 
  • 存在于缓存中!
  • 可以加载
[3]

[4]中,我们看到当IVSoftware.Portable.Xml.Linq尝试解决类型和

Could not load...
时,实际的吸烟线问题发生了。顺便说一句,这根本不是我在看的地方。这意味着
nuspec
文件中 Xml.Linq nupkg 的条目很有可能存在错误,值得进一步调查。

还有

[3][4]中,它似乎表明它正在“寻找”具有正确的“PublicKeyToken”的正确程序集。奇怪的是它找不到它,但是this是可调试的,因为我们可以看到断开连接的位置

此外

1[2]中,我们注意到版本1.0.6和1.0.7之间存在PublicKeyToken

PublicKeyToken=ef60c83b99c9b20e
PublicKeyToken=b9a82a88b12aeb62
之间存在差异的潜在问题。

© www.soinside.com 2019 - 2024. All rights reserved.