如何检入代码,哪些程序集被引用但未加载? (.NET 6.0)

How to check in code, which assemblies are referenced but not loaded? (.NET 6.0)

更新:

这个问题比我想象的更难解释。

  1. 我有 2 个项目。 (.NET 6.0)
  2. 每个项目都是一个 NuGet 包。
  3. 包不能相互依赖。 (每一个必须能够单独使用。)
  4. 如果包 B 检测到包 A 被引用( 我的意思是在 .csproj 中使用 <ProjectReference><Package Reference> 标签file - 它应该加载包 A 并从中执行一个方法。

现在我已经这样做了:

(套餐B码)

try {
    var assembly = Assembly.Load("A");
    var type = assembly.GetTypes.FirstOrDefault(t => t.Name == "MyKnownType");
    var instance = (IApiOfA)Activator.CreateInstance(t);
    instance.MethodOfA(someDataIHaveInB);
}
catch { }

我讨厌滥用异常。我的问题是如何跳过异常部分。

查询 AppDomain.CurrentDomain 没有帮助 - 它只获取加载的程序集。 Assembly.GetEntryAssembly().GetReferencedAssemblies() 也不起作用,当我显式加载它时,它甚至不显示我的目标程序集。 AppDomain.CurrentDomain.Evidence 在 .NET 6.0 中不可用。

有什么线索吗?

另一项更新: 这个:Check if Assembly Exists by name before loading it

正如其他人所说:异常并不总是那么糟糕。也许它们不是最优雅的方式,但需要权衡取舍。一项简单的检查将在应用程序开发中节省大量时间。软件包的作用很容易被忽视,并导致浪费大量时间来弄清楚为什么它不起作用。现在,当 A 和 B 包含在项目中时,将始终进行正确的交互并且两者都不会失败。如果只有其中一个包 - 没有问题,问题就不存在了。如果两者都使用,则它们合作。所以我只是在寻找微优化:)

您将需要一个自定义构建步骤,将所有引用的列表嵌入生成的可执行文件中。 Microsoft 工具不会,它们只为那些实际使用和需要的依赖项发出元数据(尽管它们实际上不必在 运行 时间出现,因为依赖项的延迟加载任何不需要的方法使用缺少的依赖项仍然可以 运行 正确)。

向项目文件添加更多 <PackageReference> 条目不会导致编译器输出发生任何变化,它只是允许您使用它们编写代码,而这些代码的存在会影响输出.

我目前的解决方案,在 Windows 和 Linux 上测试,使用单个文件构建。

/// <summary>
/// Resolves available API members.
/// </summary>
internal static class ApiResolver {

    /// <summary>
    /// Gets an instance of the specified type.
    /// If it's not already loaded, the target assembly will be loaded.
    /// </summary>
    /// <typeparam name="TInterface">Type interface.</typeparam>
    /// <param name="assemblyName">Assembly name.</param>
    /// <param name="typeName">Type name.</param>
    /// <returns>Instance or null if not found.</returns>
    public static TInterface? GetInstance<TInterface>(string assemblyName, string typeName) where TInterface : class {
        Type? type;
        try {
            var assembly = Assembly.Load(assemblyName);
            type = assembly.GetType(typeName);
        }
        catch { return null; }
        return type is null ? null : (TInterface?)Activator.CreateInstance(type);
    }

}

它returns如果无法获取实例则为null。 所以它可以像这样很好地使用:

var myTarget = ApiResolver.GetInstance<IMyTargetApi>("OtherModule", "TheClass");
myTarget?.DoSomeStuff(withSomeData);

当然有一个要求就是目标class必须实现一个已知的接口。但是我的包裹满足了这个要求。如果不满足,使用Reflection仍然可以解决,但那会很乱。