遗留和 SDK-style C# 项目之间神秘的名称解析差异

Mysterious name resolution differences between legacy and SDK-style C# projects

我在尝试将 .NET 4.6.1 项目的遗留解决方案转换为新的 SDK-style 项目格式时遇到了这个令人困惑的 names-resolution 问题。我能够创建一个最小的重现解决方案 LegacyVsSdkStyleProjectNameResolution,它位于 GitHub 此处:

https://github.com/PaloMraz/LegacyVsSdkStyleProjectNameResolution.git

解决方案包含:

(请原谅 non-intuitive 程序集/命名空间/class 名称——我无法使用原始名称,也无法设计出更可行的名称。

依赖项如图所示:

问题是,Legacy.Common.Configuration 项目使用此 Bundle class 声明成功编译:

using Legacy.Common.Data;

namespace Legacy.Common.Configuration
{
  public class Bundle
  {
    public Person Person { get; set; }
  }
}

但是Sdk.Common.Configuration产生了编译错误CS0118('Person'是一个命名空间,但像类型一样使用):

using Sdk.Common.Data;

namespace Sdk.Common.Configuration
{
  public class Bundle
  {
    public Person Person { get; set; }
  }
}

谁能解释一下,为什么 Sdk.Common.Configuration 项目中的 C# 编译器将 Person 类型符号错误地解析为命名空间 Sdk.Common.Person,但在 Legacy.Common.Configuration 中却解析了它正确地 Legacy.Common.Data.Person class?

在SDK-style个项目中,一个项目会自动继承它的依赖项所依赖的所有东西。在遗留项目中,这必须手动完成,工具会插入对新依赖项所依赖的所有事物的显式引用。

因此在您的 SDK-style 项目中,Sdk.Common.Configuration 继承了对 Sdk.Common.Person.Management 的引用,因为它引用了 Sdk.Common.Data.


Sdk.Common.Person.Management定义命名空间Sdk.Common.Person:

namespace Sdk.Common.Person.Management
{
  ...
}

虽然 Sdk.Common.Data 定义 class Sdk.Common.Data.Person.:

namespace Sdk.Common.Data
{
  public class Person
  {
  }
}

Sdk.Common.Configuration 然后这样做:

using Sdk.Common.Data;

namespace Sdk.Common.Configuration
{
  public class Bundle
  {
    public Person Person { get; set; }
  }
}

在那里,编译器在Sdk.Common.Configuration(和Sdk.Common,以及Sdk)中搜索Person before它认为using。它找到 Sdk.Common.Person 这是一个名称空间,并抱怨因为您正在使用名称空间作为类型。

如果在命名空间中包含 using,此顺序将翻转,编译器将首先搜索 Sdk.Common.Data ,然后找到 Sdk.Common.Data.Person class:

namespace Sdk.Common.Configuration
{
  using Sdk.Common.Data;

  public class Bundle
  {
    public Person Person { get; set; }
  }
}

See this answer for details.


至于如何解决这个问题,首先不要定义同名的class和命名空间。如果您无法避免这种情况,您可以如上所示更改 using 的位置,或者使用 Person class.[=27 的 fully-qualified 名称=]

如果您想要反映 Sdk.Common.Data 的引用未被 Sdk.Common.Configuration 继承的遗留行为,请在包括 [=59] 的 ProjectReference 上使用 PrivateAsserts="All" =].

<ProjectReference Include="..\Sdk.Common.Person.Management\Sdk.Common.Person.Management.csproj" PrivateAssets="All" />

这说明 Sdk.Common.Person.Management 是私有依赖项,它不会被任何引用 Sdk.Common.Data 的东西继承。