为什么部分名称空间计为名称空间

时间:2020-04-29 00:04:44

标签: c# .net-core .net-core-3.1

我有一个看起来像这样的命名空间:

namespace MyCompany.AspDotNet.Extensions.HttpClient

然后我有一个在该文件中声明的方法,如下所示:

public static async Task<HttpClient> AddAuthentication(this HttpClient httpClient)

出现错误,提示:

HttpClient是一个命名空间,但其使用方式类似于类型
类型名称是预期的,但找到了名称空间

测试表明,在命名空间中以点分隔的任何值将与类型冲突。

我的问题是,为什么要这样做?

我想了解.Net将名称空间中每个点分隔的部分本身视为一个名称空间所获得的价值。可以仅以某种方式使用命名空间的一部分吗?

作为一个附带的问题,是否有一个公认的解决方法?想到的想法是:

  • 下划线间距:MyCompany_AspDotNet_Extensions_HttpClient
  • 小写命名:mycompany.aspdotnet.extensions.httpclient
  • 完全引用所有冲突的类型Task<HttpClient>Task<System.Net.Http.HttpClient>
  • 在我的命名空间名称中不要使用任何类型:MyCompany.AspDotNet.Extensions.WebCalls

我不是大多数人的粉丝。但是,如果我必须选择一个,那么我将选择最后一个。但是当我这样做时,我发现我正在尝试为已经有好名字的东西找到另一个名字。

3 个答案:

答案 0 :(得分:2)

编译器首先查看当前名称空间以进行类型解析,但发现冲突,因为该名称空间与您要扩展的类型具有相同的名称。

解决此问题的一种方法是指定在扩展方法中引用的标准类型名称,因为单独的名称会与(更本地的)名称空间冲突:

namespace MyCompany.Extensions.HttpClient
{
    public static class HttpClientExtensions
    {
        public static async Task<System.Net.Http.HttpClient> AddAuthentication(
            this System.Net.Http.HttpClient httpClient)
        {
            // Extension method implementation here
        }
    }
}

解决该问题的另一种方法是将using语句放在命名空间内而不是外部,因此编译器首先找到它:

namespace MyCompany.AspDotNet.Extensions.HttpClient
{
    using System.Net.Http;

    public static class HttpClientExtensions
    {
        public static async Task<HttpClient> AddAuthentication(this HttpClient httpClient)
        {
            // Extension method implementation here
        }
    }
}

但是解决此问题的一种可能更好的方法是只为 all 扩展方法使用一个名称空间,然后为每种类型创建类,例如class HttpClientExtensions。这还将消除命名冲突,并减少所需的名称空间总数(为扩展方法使用这样的特定名称空间名称有点多余,因为它们仍然需要存在于类中)。

例如:

namespace MyCompany.ExtensionMethods
{
    public static class HttpClientExtensions
    {
        public static async Task<HttpClient> AddAuthentication(this HttpClient httpClient)
        {
            // Extension method implementation here
        }
    }
}

答案 1 :(得分:1)

正如这里的其他答案所述如何解决此问题,我将解决您的困惑:

namespace MyCompany.AspDotNet.Extensions.HttpClient

您没有一个名为MyCompany.AspDotNet.Extensions.HttpClien的命名空间。您所拥有的是嵌套在命名空间HttpClient中的命名空间Extensions嵌套在命名空间AspDotNet中的命名空间MyCompany中。这就是C#(和大多数类似语言)的工作方式。

答案 2 :(得分:1)

C#编译器就是这样工作的。当发现未知的标识符时,它将向上作用域并尝试将其与某些对象匹配。在您的情况下,这是一个名称空间。而且由于它期望类型,所以会抱怨。

如果完全限定HttpClient类型,或者即使在名称空间之后包含using指令(在这种情况下,编译器会在名称空间成为问题之前找到您的类型),都不会发生这种情况。

namespace MyCompany.AspDotNet.Extensions.HttpClient
{
  using System.Net.Http;

  // ...
  public static async Task<HttpClient> AddAuthentication(this HttpClient httpClient)
  // ...
}

通常,您不想在其名称空间中包含类名称(尽管严格来讲,您实际上并没有在此处使用它)。相反,您可以尝试按用途,技术或类似目的对类进行分组。因此,您的上一个示例(MyCompany.AspDotNet.Extensions.WebCalls)比列表中的其他示例要好。

一些例子

MyCompany.AspDotNet.Extensions.Web // every ASP.NET extension (?)
MyCompany.AspDotNet.Extensions.Client // extensions for when we act as a client
MyCompany.AspDotNet.Extensions.Communication // extensions for communicating between client and server
MyCompany.AspDotNet.Extensions.Http // only http communication extensions
MyCompany.AspDotNet.Extensions.Http.Serialization // only for some special serialization over HTTP
MyCompany.AspDotNet.Extensions // or just put everything in one namespace (and group them later, when you realize you can't find anything anymore)