为什么我不能在对象初始化期间使用部分限定命名空间?

14

我怀疑这是一个经常被问到的问题,但我没有找到答案。

如果我在文件中很少使用某个类型,我通常会使用完全限定的命名空间或在文件顶部添加using namaspacename以便写出new ClassName()

但是如果只添加了命名空间的一部分呢?为什么编译器找不到该类型并抛出错误?

考虑以下嵌套命名空间中的类:

namespace ns_1
{
    namespace ns_1_1
    {
        public class Foo { }
    }
}

所以现在如果我想初始化这个类的一个实例,它可以按以下方式工作:

using ns_1.ns_1_1;

public class Program
{
    public Program()
    {
        // works, fully qualified namespace:
        var foo = new ns_1.ns_1_1.Foo();
        // works, because of using ns_1.ns_1_1:
        foo = new Foo();
    }
}

但是以下方法不起作用:
using ns_1;

public class Program
{
    public Program()
    {
        // doesn't work even if using ns_1 was added
        var no_foo = new ns_1_1.Foo();
    }
}

它抛出编译器错误:

找不到类型或命名空间名称“ns_1_1”(是否缺少 using 指令或程序集引用?)。

我认为这是因为 ns_1_1 被视为包含另一个类 Foo 的类,而不是一个命名空间,这样是正确的吗?

我还没有找到语言规范,这在哪里记录?为什么编译器不能智能地检查是否存在类命名空间(部分)?


以下是另一个更具体的示例:

using System.Data;

public class Program
{
    public Program()
    {
        using (var con = new SqlClient.SqlConnection("...")) // doesn't work
        {
            //... 
        }
    }
}

编辑: 现在我知道为什么这对我来说看起来非常奇怪了。在VB.NET中,它可以毫无问题地工作:

Imports System.Data

Public Class Program
    Public Sub New()
        Using con = New SqlClient.SqlConnection("...") ' no problem

        End Using
    End Sub
End Class
4个回答

7

这种显而易见的方法不幸地无法起作用,但您可以通过别名命名空间来完成所有这些操作:

using ns_1_1 = ns_1.ns_1_1;

public class Program
{
    public Program()
    {
        var no_foo = new ns_1_1.Foo();
    }
}

很棒的答案!这就是我们正在使用的方法,可以很好地解决命名空间组织问题。例如,如果您有更多的Customer类,一个在xx.xx.Client命名空间中,一个在xx.xx.Server中,一个在xx.xx.Backoffice中,并且它们都在BLCustomer中使用,您可以轻松缩短这些完全限定名称并使用Client.Customer。 - Haco

4

根据文档

创建一个 using 指令,可以使用命名空间中的类型而无需指定命名空间。 using 指令不会使你访问指定命名空间中嵌套的任何命名空间。

因此,using 只能包含指定命名空间中定义的类型(而非命名空间)。如果要访问嵌套命名空间的类型,则需要明确指定该命名空间,并使用 using 指令,就像在第一个示例中所做的那样。


2
谢谢。这似乎回答了我的问题。但是,为什么C#编译器不够聪明(或者不想)在“using”中添加外部命名空间的命名空间?(也许这是向E. Lippert提出的问题)。正如我回答中所示,VB.NET支持它。 - Tim Schmelter
1
为了避免歧义,也许可以举个例子。比如说,如果你有另一个不是嵌套的 SqlClient 命名空间,并且包含另一个 SqlConnection 类,那会发生什么?你在 VB 中尝试过吗?它是如何避免歧义的?它是否要求你指定完全限定名称? - Selman Genç
2
然后VB在其他SqlClient命名空间中使用新类。它似乎胜出,因为它是完全限定的,而模糊类型只是部分限定的。 - Tim Schmelter

2
这在标准文档中有说明,链接为3.8 Namespace and Type Names,但是有点复杂难懂。
其要点是,在命名空间的每个层级以及外部层级中,只会在该命名空间中查找部分命名空间引用,而不会检查using指令。
在你的示例中,如果在以下任何位置找到Foo,则会找到ns_1_1.Foo:
Program.Program.ns_1_1.Foo
Program.ns_1_1.Foo
ns_1_1.Foo

1
谢谢。我仍然不清楚为什么我不能在C#中使用它,而不是VB.NET。但我认为我知道Erip Lippert会给出的答案:因为该功能的预计收益不值得实现成本。 - Tim Schmelter
那听起来有点像他,我同意 :) - Lasse V. Karlsen

2

如果您当前的类是部分命名空间的一部分,则部分命名空间仅起作用。使用语句不被视为通过部分命名空间访问类型。

例如,这将起作用,因为您当前的命名空间是 ns_1

namespace ns_1
{
    public class Program
    {
        public Program()
        {
            var no_foo = new ns_1_1.Foo();
        }
    }
}

有趣的是,如果你将它改为'namespace ns_1.ns_2_2','new ns_1_1.Foo()'仍然可以工作。看起来它首先在当前命名空间中查找,然后在当前命名空间的父级中查找,以此类推。 - Triynko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接