【问题标题】:C# Hidden ReferencesC# 隐藏引用
【发布时间】:2014-09-03 22:50:03
【问题描述】:

我正在尝试确定我的程序集需要编译哪些 dll。我在一个解决方案中有两个示例项目,即 Scratch 和 ScratchTest。这是 Scratch 的 Program.cs:

using System.ServiceProcess;

namespace Scratch
{
    public class A : ServiceBase
    {
        static void Main(string[] args)
        {
        }
    }
}

Scratch 引用了 System.ServiceProcess.dll。

这里是 ScratchTest 的 program.cs:

namespace ScratchTest
{
    class Program
    {
        static void Main(string[] args)
        {
        Scratch.A o;
        }
    }
}

ScratchTest 必须同时引用 Scratch 和 System.ServiceProcess.dll。但是,生成的 ScratchTest.dll 没有引用 System.ServiceProcess.dll,只有 Scratch。我通过查看都知道这一点

Assembly.GetReferencedAssemblies()

并使用 .net 反射器。所以我的问题是,我怎么知道 ScratchTest 需要 System.ServiceProcess.dll 才能编译?特别是考虑到 SratchTest 不一定要引用 Scratch 的所有引用,因为可能存在一些冲突的引用。谢谢,埃里克

【问题讨论】:

  • 了解您要如何处理这些信息会很有用。另外,请记住直接依赖和间接依赖之间的区别。 ScratchTest 直接依赖于 Scratch。 ScratchTest 对 System.ServiceProcess.dll 有间接依赖,因为 System.ServiceProcess.dll 是 Scratch 的直接依赖。
  • 我正在尝试做的事情有点难以解释。我正在尝试将项目从不同的构建系统转换为 msbuild。因此,我正在编写 .csproj 文件。原始构建系统不需要引用 System.ServiceProcess.dll,因为它默认包含在 csc.rsp 中。我正在使用的新构建系统强制使用标志 /noconfig+,这意味着不包含 csc.rsp,我必须明确指定引用,并且我正在尝试检测我需要哪些。
  • 有趣。因此,您有多个 .Net 项目,所有这些项目都曾经依赖 csc.rsp 进行依赖性检测。现在,您要为每个项目创建一个项目文件,并在每个项目中包含正确的依赖项。假设某些项目将依赖于其他项目是否正确,在这种情况下,您更愿意将它们添加为项目引用而不是 dll 引用?
  • 另外,您是否使用 Visual Studio 作为您的 IDE?
  • 我相信它们是项目引用,是的,我使用的是 VS2013。

标签: c# .net dll .net-assembly


【解决方案1】:

首先,您面临的问题并非特定于 ServiceBase 类。它与 CLR 如何准确地检测 C# 程序的类型依赖关系并加载引用的程序集有关。 C# 编译器只是在编译时提前给您一个错误,因为当 CLR 尝试运行您的程序时,同样会在运行时失败。这是我在解释您的问题的解决方案时的假设:

ScratchTest 是您的启动项目,尽管您在解决方案中定义了两个入口点,因为“Scratch”和“ScratchTest”项目中都存在 Main 方法。为避免混淆,您的解决方案通常应该只有一个主要方法(入口点),尽管它对您当前的问题没有影响。

解决方案:当您在 scratchTest 项目中引用 A 类时,您不仅指代 A 类,还指代 ServiceBase 类,因为“A”类继承自它。因此,当编译器尝试编译您的 ScratchTest 项目时,它会尝试在当前引用的程序集中查找依赖类型,即“A”和ServiceBase。这里的重点是 CLR 总是尝试仅在程序集中查找依赖项类型,这些程序集中的引用直接存在于您尝试加载的程序集本身的清单元数据中(在本例中为 ScratchTest)。永远不会像您构建解决方案那样以递归方式搜索依赖类型。本质上,期望 CLR 在所有引用的程序集中搜索依赖项类型,进而在 .Net 应用程序启动时对其引用的程序集产生巨大的性能影响。

同时,在您创建的大多数 C# 项目中,通常会引用 MsCorLibSystemSystem.CoreSystem.Data 等核心 .Net 库。然后考虑这种情况,否则如果 CLR 实现了通过引用的程序集递归查找依赖项类型的逻辑,那么它会通过在搜索依赖项类型时每次检查它是否已经通过特定程序集来做出额外的努力这会进一步损害启动性能。

要修复您的代码,您可以做以下两件事:

  • 按照 C# 编译器的建议,将 System.ServiceProcess.dll 的引用添加到 ScratchTest 项目。

  • 在“ScratchTest”项目本身中使用类 A,因为它已经包含对 System.ServiceProcess.dll 的引用

【讨论】:

  • 我最终不得不对陷入这种情况的 dll 进行特殊处理,并强制将它们包含在 ScratchTest 中。幸运的是,很少有 dll 具有与此相同的使用模式。
【解决方案2】:

我认为您不需要在测试文件上显式调用 System.ServiceProcess。

Test 文件没有使用对 System.ServiceProcess 中任何方法或类的任何引用,只是使用了 Scratch。

您不需要要求引用的类使用的所有库,只需要您的类当前使用的库。

所以 ScratchTest 只使用 Scrath,而 Scratch 使用 System.ServiceProcess。

【讨论】:

  • 尝试在VS中编译这个(我用的是2013)。如果 ScratchTest 没有对 System.ServiceProcess 的显式引用,它将不会编译。
猜你喜欢
  • 2011-08-05
  • 1970-01-01
  • 1970-01-01
  • 2017-03-13
  • 2011-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多