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 源上。
TypeA
将在这个特定的不存在的版本1.0.6中得到解决?看起来像是从帽子里拿出来的,但我知道它是从某个地方获取这个值的......
TypeA
?
<AssemblyOriginatorKeyFile>
,对吧?
对我来说,错误消息毫无意义,本质上是:
我找不到
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;
}
}
}
}
在
和[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 和[4]中,我们看到当IVSoftware.Portable.Xml.Linq
尝试解决类型和
Could not load...
时,实际的吸烟线问题发生了。顺便说一句,这根本不是我在看的地方。这意味着 nuspec文件中
Xml.Linq
nupkg 的条目很有可能存在错误,值得进一步调查。还有在[3]和[4]中,它似乎表明它正在“寻找”具有正确的“PublicKeyToken”的正确程序集。奇怪的是它找不到它,但是this是可调试的,因为我们可以看到断开连接的位置。
此外在和[2]中,我们注意到版本1.0.6和1.0.7之间存在PublicKeyToken
与
PublicKeyToken=ef60c83b99c9b20e
和PublicKeyToken=b9a82a88b12aeb62
之间存在差异的潜在问题。