使用静态类作为名称空间


21

我看到其他开发人员使用静态类作为名称空间

public static class CategoryA
{
    public class Item1
    {
        public void DoSomething() { }
    }
    public class Item2
    {
        public void DoSomething() { }
    }
}

public static class CategoryB
{
    public class Item3
    {
        public void DoSomething() { }
    }
    public class Item4
    {
        public void DoSomething() { }
    }
}

要实例化内部类,它将类似于以下内容

CategoryA.Item1 item = new CategoryA.Item1();

理由是可以使用“ using”关键字隐藏名称空间。但是,通过使用静态类,必须指定外层类名称,这样可以有效保留名称空间。

Microsoft在指南中建议不要这样做。我个人认为这会影响可读性。你怎么看?


1
是否需要实现中存在的名称空间取决于实现者。为什么要在其上强制使用名称空间(以及该名称空间中的伪名称空间)?
Craige

可能是出于分组目的?就像有很多子类,并且通过将子类分组为静态类一样。那使意图清楚吗?
2011年

将子类放在子命名空间中是否也会使意图不清楚?同样,这是通过文档解决的问题类型。
Craige

Answers:


16

使用静态类作为名称空间无法达到拥有名称空间的目的。

关键区别在于:

如果您将CategoryA,定义CategoryB<为名称空间,以及应用程序何时使用两个名称空间:

CategoryA::Item1 item = new CategoryA::Item1(); 
CategoryB::Item1 item = new CategoryB::Item1();

在这里,如果CategoryAor CategoryB是静态类而不是名称空间,则该应用程序的用法与上述几乎相同。

但是,如果将其定义为名称空间,并且应用程序仅使用1个名称空间(不包括CategoryB),则在这种情况下,应用程序实际上可以使用以下名称空间

using namespace CategoryA; 
Item1 item = new Item1(); 

但是,如果您将其定义CategoryA为静态类,则以上未定义!CategoryA.something每次都要写一个。

应该使用命名空间来避免命名冲突,而当类分组与系统模型相关时,应使用类层次结构。


另外,如果有人不想使用名称空间,甚至不使用类,也可以使用can :(using Item1 = CategoryA.Item1我认为这适用于嵌套类,就像它适用于名称空间一样)
George Duckett 2012年

1
在C ++中,ADL不适用于类范围。它与命名空间范围一起使用。因此,在C ++中,命名空间不仅是自然的选择,但是正确地道的选择
纳瓦兹

我认为OP的目的是避免通过using关键字隐藏名称空间。他想强迫用户每次写文章。也许他的名字空间就像var s = new HideMe.MyPhoneNumberIs12345678.TheRealUsefulClass()
Gqqnbig

5

这里发生的一切当然不是惯用的C#代码。

也许其他人正在尝试实现模块模式-这将使您具有函数,操作等以及“命名空间”中的类(在这种情况下为静态类)?


我同意,看起来很奇怪。
marko

4

首先,每个类都应该在名称空间中,因此您的示例实际上将更像是:

SomeNamespace.CategoryA.Item1 item = new SomeNamespace.CategoryA.Item1();

也就是说,当您可以很好地定义这样的名称空间时,我看不到这种代码体操的好处:

namespace SomeNamespace.CategoryA { ... }

如果您可能有一天想在上层类中存储一些静态方法,这可能是有道理的,但C#创建者并没有想到这些,可能会使其他人难以理解-我会浪费很多时间考虑为什么要这么做,并考虑是否缺少一些提供解释的源文件。


那么,为什么枚举是规则例外
sq33G 2011年

那是一个不同的问题:)但是我仍然不会仅仅为了在其中定义枚举而定义一个静态类。
zmilojko 2011年

1

与Java,JavaScript和.NET相关的命名空间还不完整,仅允许存储类,而其他诸如常量或全局方法之类的命名空间则不完整。

即使有些人不推荐,许多开发人员也使用“静态类”或“静态方法”技巧。


0

我知道这是一个古老的问题,但是使用类作为名称空间(当时是非静态名称空间)的一个非常合理的理由是C#不支持参数或通用名称空间的定义。我在这里写了一篇关于这个主题的博客文章:http://tyreejackson.com/generics-net-part5-generic-namespaces/

其要点是,当使用泛型来抽象大量样板代码时,有时有必要在相关类和接口之间共享多个泛型参数。这样做的常规方法是在每个接口和类签名中重新定义通用参数,约束以及所有参数。随着时间的流逝,这可能导致参数和约束的激增,更不用说不断地通过将类型参数从一种类型转发到相关类型的类型实参来限定相关类型。

使用外部Generic类并在其中嵌套相关类型可以极大地使代码干燥并简化其抽象。然后,可以使用提供所有具体细节的具体实现派生参数化名称空间类。

这是一个简单的示例:

public  class   Entity
                <
                    TEntity, 
                    TDataObject, 
                    TDataObjectList, 
                    TIBusiness, 
                    TIDataAccess, 
                    TIdKey
                >
        where   TEntity         : Entity<TEntity, TDataObject, TDataObjectList, TIBusiness, TIDataAccess, TIdKey>, subclassed
        where   TDataObject     : Entity<TEntity, TDataObject, TDataObjectList, TIBusiness, TIDataAccess, TIdKey>.BaseDataObject, subclassed
        where   TDataObjectList : Entity<TEntity, TDataObject, TDataObjectList, TIBusiness, TIDataAccess, TIdKey>.BaseDataObjectList, subclassed
        where   TIBusiness      : Entity<TEntity, TDataObject, TDataObjectList, TIBusiness, TIDataAccess, TIdKey>.IBaseBusiness
        where   TIDataAccess    : Entity<TEntity, TDataObject, TDataObjectList, TIBusiness, TIDataAccess, TIdKey>.IBaseDataAccess
{

    public class    BaseDataObject
    {
        public TIdKey Id { get; set; }
    }

    public class BaseDataObjectList : Collection<TDataObject> {}

    public interface IBaseBusiness
    {

        TDataObject     LoadById(TIdKey id);
        TDataObjectList LoadAll();
        void            Save(TDataObject item);
        void            Save(TDataObjectList items);
        void            DeleteById(TIdKey id);
        bool            Validate(TDataObject item);
        bool            Validate(TDataObjectList items);

    }

    public interface IBaseDataAccess
    {

        TDataObject     LoadById(TIdKey id);
        TDataObjectList LoadAll();
        void            Save(TDataObject item);
        void            Save(TDataObjectList items);
        void            DeleteById(TIdKey id);

    }

}

像这样使用:

public  class   User 
:
                Entity
                <
                    User, 
                    User.DataObject, 
                    User.DataObjectList, 
                    User.IBusiness, 
                    User.IDataAccess, 
                    Guid
                >
{
    public class DataObject : BaseDataObject
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

    public class DataObjectList : BaseDataObjectList {}

    public interface IBusiness : IBaseBusiness
    {
        void DeactivateUserById(Guid id);
    }

    public interface IDataAcccess : IBaseDataAccess {}
}

消耗这样的导数:

public class EntityConsumer
{
    private User.IBusiness       userBusiness;
    private Permission.IBusiness permissionBusiness;

    public EntityConsumer(User.IBusiness userBusiness, Permission.IBusiness permissionBusiness) { /* assign dependencies */ }

    public void ConsumeEntities()
    {
        var users       = new User.DataObjectList();
        var permissions = this.permissionBusiness.LoadAll();

        users.Add
        (new User.DataObject()
        {
            // Assign property values
        });

        this.userBusiness.Save(users);

    }
}

以这种方式编写类型的好处是增加了类型安全性,并减少了抽象类中类型的转换。相当于ArrayListvs List<T>在更大范围内。

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.