【问题标题】:Why can't i use partly qualified namespaces during object initialization?为什么我不能在对象初始化期间使用部分限定的命名空间?
【发布时间】:2014-09-23 13:55:47
【问题描述】:

我怀疑这是一个以前被问过很多次但我还没有找到的问题。

如果我不经常在文件中使用该类型,或者我在文件顶部添加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 而不是命名空间的类,这是正确的吗?

我还没有找到语言规范,这是在哪里记录的?为什么编译器不够聪明,无法检查是否存在类命名空间(-part)?


这是另一个不太抽象的例子:

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

【问题讨论】:

    标签: c# types compiler-construction compiler-errors namespaces


    【解决方案1】:

    这在3.8 Namespace and Type Names 的标准中有记录,但遵循起来有点复杂。

    部分命名空间引用仅在其出现的命名空间中查找,并且每一层都向外查找。 using-directives 未检查。

    在您的示例中,如果在以下任何位置找到 Foo,则将找到 ns_1_1.Foo

    Program.Program.ns_1_1.Foo
    Program.ns_1_1.Foo
    ns_1_1.Foo
    

    【讨论】:

    • 谢谢。目前还不清楚为什么我不能在 C# 中使用它而不是 VB.NET。但我想我知道 Erip Lippert 会给出的答案:因为该功能的估计收益不值得它的实施成本。
    • 听起来有点像他,我同意 :)
    【解决方案2】:

    documentation 说:

    创建 using 指令以使用命名空间中的类型,而无需指定命名空间。 using 指令不允许您访问嵌套在您指定的命名空间中的任何命名空间。

    所以using 只包括在指定命名空间中定义的类型(不是命名空间)。为了访问嵌套命名空间的类型,您需要使用 using 指令明确指定它,就像您在第一个示例中所做的那样。

    【讨论】:

    • 谢谢。这似乎回答了我的问题。但是,为什么 C# 编译器不够聪明(或不想)包含在 using 中添加的外部命名空间的命名空间? (也许这是 E. Lippert 的问题)VB.NET 支持它,如我的回答所示。
    • 为了避免歧义,也许......例如,如果您有另一个未嵌套的 SqlClient 命名空间并包含另一个 SqlConnection 类,会发生什么情况?你在VB中试过这个吗?它如何避免歧义?是否要求您指定完全限定的名称?
    • 那么 VB 确实使用了另一个 SqlClient 命名空间中的新类。它似乎赢了,因为它是完全合格的,而模棱两可的类型只是部分合格。
    【解决方案3】:

    仅当您当前的类是该部分命名空间的一部分时,部分命名空间才会起作用。通过部分命名空间访问类型时不考虑使用语句。

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

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

    【讨论】:

    • 有趣的是,如果您将其更改为“命名空间 ns_1.ns_2_2”,“新 ns_1_1.Foo()”仍然有效。似乎它首先在当前命名空间中查找,然后在当前命名空间的父级中查找,依此类推。
    【解决方案4】:

    不幸的是,这种显而易见的方式不起作用,但您可以通过别名命名空间来实现所有这些:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-04
      • 1970-01-01
      • 2012-12-06
      • 2010-10-03
      • 1970-01-01
      • 2016-02-23
      • 1970-01-01
      • 2015-02-10
      相关资源
      最近更新 更多