遗留和 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
解决方案包含:
- 3 个针对 .NET Framework 4.6.1 的遗留项目位于“遗留”解决方案文件夹中;项目名称以“Legacy.”开头。
- 3 SDK-style 个以 .NET 为目标的项目位于“Sdk”解决方案文件夹中;项目名称以“Sdk.”开头。
(请原谅 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 的东西继承。
我在尝试将 .NET 4.6.1 项目的遗留解决方案转换为新的 SDK-style 项目格式时遇到了这个令人困惑的 names-resolution 问题。我能够创建一个最小的重现解决方案 LegacyVsSdkStyleProjectNameResolution
,它位于 GitHub 此处:
https://github.com/PaloMraz/LegacyVsSdkStyleProjectNameResolution.git
解决方案包含:
- 3 个针对 .NET Framework 4.6.1 的遗留项目位于“遗留”解决方案文件夹中;项目名称以“Legacy.”开头。
- 3 SDK-style 个以 .NET 为目标的项目位于“Sdk”解决方案文件夹中;项目名称以“Sdk.”开头。
(请原谅 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 的东西继承。