为什么我可以在 ASP.NET 5 项目中引用一个不包含对该程序集的引用的程序集?

Why can I reference an assembly in an ASP.NET 5 project that doesn't include a reference to that assembly?

我有一个名为 Foo 的 DNX 4.5.1 ASP.NET 5 项目和一个名为 Bar 的 class 库项目。 Foo 引用了 Bar,而 Bar 引用了一个名为 Baz 的 nuget 包。

在 Foo 中,我可以使用 Baz 中定义的类型,尽管 Foo 没有引用 nuget 包。看起来 Foo 可以访问 Bar 引用的任何类型。这是为什么?这不是完全打破了抽象的概念吗?

不,只要您也在 Foo 中安装 Baz NuGet 包,它就不会破坏抽象,因为您声明了依赖项。 Baz 库具有 public classes 的简单事实意味着任何引用它的 exe 或 dll 文件都可以使用那些 classes.

由于 Foo 需要 Bar,而 Bar 需要 Baz,因此在编译 Foo 时 Baz.dll 文件应该出现在 bin/ 输出文件夹中,因为 Foo 在 Bar 中需要 classes。这意味着 Foo 中文件顶部的简单 using 指令会导致 CLR 导入 Baz.dll 文件。

现在如果 Foo 需要直接使用 Baz 中定义的 classes,我建议安装 Baz 项目作为 Foo 的依赖项。两个库需要同一个第三方库是可以的。您只需要确保 Foo 和 Bar 都需要相同的版本。

如果 Foo 和 Bar 需要不同的版本,那么我建议在 Bar 中创建代理 classes 或接口来封装你需要的 Baz 的行为,这样 Foo 项目就不需要直接知道关于巴兹

举个具体的例子吧

示例:使用 NHibernate 的博客 Web 应用程序

无需深入研究或对 "best practices" 做出任何判断,此示例围绕博客的 ASP.NET MVC 项目展开。它有一个用于数据访问和业务 class 的 class 库。该库安装 NHibernate NuGet 包。

  • Foo 是 "Blog.Mvc" 项目,一个 ASP.NET MVC 应用程序

  • Bar 是 "Blog.Core" 项目,一个包含存储库 classes 和接口的 class 库,以及 "Domain Models" 或业务 classes.

  • Baz 是 NHibernate

所以问题变成:

Should the "Blog.Mvc" application directly uses classes from NHiberate?

没有。 "Blog.Core" 项目应该使用存储库接口提供一个抽象层:

Blog.Core

首先,"Domain Model"或业务class:

public class Blog
{
    public virtual int Id { get; protected set; }
    public virtual string Name { get; set; }
}

博客存储库的 public 界面:

public interface IBlogRepository
{
    Blog Find(int id);
}

现在实现接口,引用classes和与NHibernate直接相关的接口:

public class BlogRepository : IBlogRepository
{
    private NHibernate.ISession session;

    private NHibernate.ISession Session
    {
        get
        {
            if (session == null)
                session = NHibernateSessionHelper.GetSession();

            return session;
        }
    }

    public Blog Find(int id)
    {
        return Session.Get<Blog>(id);
    }
}

MVC 项目控制器通过其接口使用存储库:

public class BlogsController : Controller
{
    public BlogsController(IBlogRepository repository)
    {
        this.repository = repository;
    }

    private IBlogRepository repository;

    public ActionResult Edit(int id)
    {
        Blog blog = repository.Find(id);

        if (blog == null)
            return HttpNotFound();

        BlogForm viewModel = new BlogForm(blog);

        return View(viewModel);
    }
}

虽然这可能不是您的确切情况,但此示例中概述的关注点分离使您的问题没有实际意义。

如果 Foo 在 Baz 中需要 classes,请将其声明为依赖项。如果不是,请不要在 Foo 项目中使用 Baz 中声明的 classes。如果 Foo 需要来自 Bar 的功能将某些行为委托给 Baz,那么只要 Foo 没有传递 Baz 中定义的 classes 的任何对象,这就不会破坏抽象。 Bar 需要创建自己的 classes 作为数据传输对象、代理 classes 或某种实现 Bar 中定义的接口以供 Foo 使用的对象。