命名空间和类具有相同的名称?


95

我正在组织一个库项目,我有一个名为的中央管理器类,Scenegraph以及生活在Scenegraph名称空间中的许多其他类。

我真正想要的是将景图MyLib.Scenegraph作为其他类MyLib.Scenegraph.*,但是似乎唯一的方法是Scenegraph在Scenegraph.cs文件中使所有其他类成为内部类,这太笨拙了。

取而代之的是,我将其组织为Mylib.Scenegraph.ScenegraphMyLib.Scenegraph.*,但是我发现Visual Studio在某些情况下对于我是引用类还是命名空间感到困惑。

是否有一种组织此程序包的好方法,以便用户使用它而又不会在无法维护的混乱中将我的所有代码混在一起?

Answers:


112

我不建议您像命名空间那样命名一个类,请参见this

框架设计指南在第3.4节中说“不要对名称空间和名称空间使用相同的名称”。那是:

namespace MyContainers.List 
{ 
    public class List {  } 
}

为什么这样不好?哦,让我数一数。

您可能会陷入一种情况,即您认为自己是在指一件事,而实际上是在指另一件事。假设您最终遇到这种不幸的情况:您正在编写Blah.DLL并导入Foo.DLL和Bar.DLL,不幸的是,它们都具有称为Foo的类型:

// Foo.DLL: 
namespace Foo { public class Foo { } }

// Bar.DLL: 
namespace Bar { public class Foo { } }

// Blah.DLL: 
namespace Blah  
{   
using Foo;   
using Bar;   
class C { Foo foo; } 
}

编译器给出错误。Foo.Foo和Bar.Foo之间的“ Foo”是不明确的。笨蛋 我想我会通过完全限定名称来解决此问题:

   class C { Foo.Foo foo; } 

现在出现歧义错误“ Foo中的Foo.Foo在Foo.Foo和Bar.Foo之间是模棱两可的 ”。我们仍然不知道第一个Foo所指的是什么,并且直到我们能弄清楚这一点之前,我们甚至都不会费心试图找出第二个Foo所指的是什么。


6
这是一个有趣的观点。我对此不以为然。谢谢。我必须坦白地说,以“样式指南说”开头的论点不会打动我。我已经在样式指南中看到了很多不合理的废话。但是您在上面提出了一个很好的实用论据。无论如何,值得考虑。
user430788 2013年

5
响应说“不做什么”。而一些堆栈用户则在寻找“做什么”。有人会推荐Ant_222回答吗?
fantastory 2014年

3
如果确实遇到问题,仍然可以在名称空间之外创建类型别名。仅当您具有两个完全相同的完整标识符(名称空间+类名称)时,才需要外部别名。
Geoffrey

3
以上所有都是再见和见解。的事实是,你不应该这样做,因为C#编译器会误解它,尽管被告知很清楚发生了什么事情。例如,using Foo.Bar;以后Bar b会很清楚地引用Bar命名空间中的类(或枚举)Foo.Bar。不这样做的真正原因纯粹是C#编译器无法正确理解它,这是非常令人惊讶和不幸的。除此之外,还有其他一些建议。
TJ Crowder

2
我不明白 为什么Foo.Foo不明确?您直接对编译器说,要在这种特定情况下使用命名空间Foo中的类Foo。没有?
GuardianX

14

为名称空间和类赋予相同的名称可能会使编译器感到困惑,就像其他人所说的那样。

那怎么命名呢?

如果名称空间具有多个类,则找到一个定义所有这些类的名称。

如果名称空间只有一个类(并因此倾向于给它一个相同的名称),则将名称空间命名为ClassName NS。微软至少是这样命名命名空间的。


4
您是否有Microsoft提供的此类名称空间的示例?
撤销

我必须进行搜索,然后再回头给您。
GoTo

@sunefred我搜索了它,但是找不到。但是我绝对记得在文档中看到过它。我想在名称空间中只有一个类的情况并不多。
GoTo

9

我建议您遵循我开始microsoft.public.dotnet.languages.csharp使用MyLib.ScenegraphUtil.Scenegraph和的建议MyLib.ScenegraphUtil.*



4

只需加上我的2美分:

我有以下课程:

namespace Foo {
    public struct Bar {
    }
    public class Foo {
        //no method or member named "Bar"
    }
}

客户端是这样写的:

using Foo;

public class Blah {
    public void GetFoo( out Foo.Bar[] barArray ) {
    }
}

宽恕错误GetFoo不返回输出而不是使用out参数,编译器无法解析数据类型Foo.Bar []。它返回错误:找不到类型或名称空间Foo.Bar。

看起来,当尝试编译时,它将Foo解析为类,而在Foo类中未找到嵌入式类Bar。它还找不到名为Foo.Bar的命名空间。它无法在名称空间Foo中查找类Bar。名称空间中的点不是语法。整个字符串是一个标记,而不是由点分隔的单词。

运行.Net 4.6的VS 2015表现出了这种行为


4

即使我同意其他答案,因为您不应该将类的名称与名称空间相同,有时还是无法满足此类要求。

以我的情况为例,我不是做出这样决定的人,因此,我需要找到一种使之起作用的方法。

因此,对于那些无法更改名称空间名称或类名称的人,这里是使代码正常工作的一种方法。

// Foo.DLL: 
namespace Foo { public class Foo { } }

// Bar.DLL: 
namespace Bar { public class Foo { } }

// Blah.DLL: 
namespace Blah
{
    using FooNSAlias = Foo;//alias
    using BarNSAlias = Bar;//alias
    class C { FooNSAlias.Foo foo; }//use alias to fully qualify class name
}

基本上,我创建了名称空间“别名”,这使我可以完全限定该类,而Visual Studio的“混乱”消失了。

注意: 如果您在控件中这样做,则应避免这种命名冲突。仅当您不受有关类和名称空间的控制时,才应使用上述技术。


2
我投票赞成这是因为它是解决不完善世界的有趣方法。
user430788

2

旧帖子,但是在这里我想出一个可以帮助某人的想法:

“ ...但是似乎唯一的方法是将所有其他类都包含在Scenegraph.cs文件中的Scenegraph内部类中,这太笨拙了。”

对于许多场景,这确实是更好的实现。但是,我同意将所有代码都放在同一个.cs文件中令人讨厌(至少可以这样说)。

您可以通过将基类设置为“局部类”来解决它,然后继续在自己的文件上创建内部类(请记住,它们必须声明基类的补充,然后继续特定的内部类该文件)。

就像是...

Scenegraph.cs:

namespace MyLib
{
    public partial class Scenegraph
    {
        //Scenegraph specific implementations
    }
}

DependentClass.cs:

namespace MyLib
{
    public partial class Scenegraph
    {
        public class DependentClass
        {
            //DependentClass specific implementations
        }
    }
}

我确实认为,这与内部类的干净实现更接近,而不必使一个庞大且混乱的文件中的所有内容杂乱无章。


2

正如其他人所说,避免将类命名为其名称空间是一个好习惯。

这是来自svick的答案的一些其他命名建议这些答案是有关软件工程堆栈交易所上的一个相关问题“相同的类和名称空间名称”的:

没错,您不应该使用与名称空间相同的名称来命名名称空间。我认为您可以使用几种方法:

  • 多元化:Model.DataSources.DataSource

如果命名空间的主要目的是包含从相同基本类型继承或实现相同接口的类型,则此方法特别有效。

  • 缩短:Model.QueryStorage

如果名称空间仅包含少量类型,则可能根本不需要该名称空间。

  • 成为企业:Model.ProjectSystem.Project

这特别适用于产品重要组成部分的功能,因此应使用自己的名称。

(注意的是,上述答案的用途Model.DataSource.DataSourceModel.QueryStorage.QueryStorage.Model.Project.Project作为例子,而不是MyLib.Scenegraph.Scenegraph。)

(我还发现此处其他答案中的其他命名建议很有帮助。)


1

它是名称空间的主类时发生。因此,将名称空间放入库中是一种动机,然后如果在名称空间名称中添加“ Lib”,问题就消失了。

namespace SocketLib
{
    class Socket
    {
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.