web-dev-qa-db-ja.com

名前空間としての静的クラスの使用

静的クラスを名前空間として使用している他の開発者を見てきました

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」キーワードを使用して名前空間を非表示にできるということです。ただし、静的クラスを使用する場合は、外層クラス名を指定する必要があります。これにより、名前空間が効果的に保持されます。

マイクロソフトは ガイドライン でそれに対して助言します。個人的には読みやすさに影響すると思います。あなたの考えは何ですか?

21
user394128

名前空間として静的クラスを使用すると、名前空間を持つ目的が損なわれます。

主な違いは次のとおりです。

CategoryAを定義すると、CategoryB<名前空間として、アプリケーションが2つの名前空間を使用する場合:

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

ここで、CategoryAまたはCategoryBが名前空間ではなく静的クラスである場合、アプリケーションの使用法は上記とほぼ同じです。

ただし、名前空間として定義し、アプリケーションが使用する名前空間が1つだけの場合(CategoryBは含まれません)、その場合、アプリケーションは実際に以下を使用できます。

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

しかし、CategoryAを静的クラスとして定義した場合、上記は未定義です! 1つはCategoryA.something 毎回。

名前空間は、名前の競合を避けるために使用する必要がありますが、クラス階層は、クラスのグループ化がシステムモデルに何らかの関連がある場合に使用する必要があります。

16
Dipan Mehta

ここで何が起こっているかは、確かに慣用的なC#コードではありません。

多分これらの他の人たちはモジュールパターンを実装しようとしています-これはあなたが「名前空間」のクラス(この場合は静的クラス)だけでなく、関数、アクションなどを持つことができるようにしますか?

5
FinnNk

まず第一に、すべてのクラスは名前空間にある必要があるため、実際の例は次のようになります。

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

そうは言っても、このような名前空間を定義するだけで、この種のコード体操のメリットは見られません。

namespace SomeNamespace.CategoryA { ... }

あるクラスの静的メソッドを上位クラスレベルで保存することを考えている場合、これは理にかなっていますが、C#の作成者が考えていることではなく、他の人に読みにくくなる可能性があります。なぜあなたはこれをしたのか、そして説明を提供するソースファイルが欠けているのではないかと考えました。

4
zmilojko

Java、JavaScript、および.NET関連の名前空間は完全ではなく、クラスの格納のみを許可しますが、定数やグローバルメソッドなどの他のものは許可しません。

多くの開発者は、「静的クラス」または「静的メソッド」のトリックを使用しています。

1
umlcat

私はこれが古い質問であることを知っていますが、クラスを名前空間として(静的でないクラスとして)使用する非常に有効な理由の1つは、C#がパラメトリックまたは汎用の名前空間の定義をサポートしていないことです。私はこのまさにトピックについてブログ記事を書きました ここ:http://tyreejackson.com/generics-net-part5-generic-namespaces/

その要点は、ジェネリックを使用してボイラープレートコードの膨大なスワスを抽象化する場合、関連するクラスとインターフェース間で複数のジェネリックパラメーターを共有する必要がある場合があります。これを行う従来の方法は、ジェネリックパラメーター、制約、およびすべてを各インターフェイスおよびクラスシグネチャで再定義することです。時間の経過とともに、これはパラメーターの急増につながり、1つの型から関連する型の型の引数に型パラメーターを転送することにより、関連する型を常に修飾する必要があることは言うまでもありません。

外側のGenericクラスを使用し、関連する型をその中にネストすると、コードが劇的にDRY=簡単になり、抽象化が簡素化されます。具体的な詳細のすべてを提供する具象実装を使用して、パラメトリック名前空間クラスを派生できます。 。

これは簡単な例です:

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);

    }
}

この方法で型を作成する利点は、型の安全性が追加され、抽象クラスでの型のキャストが少なくなることです。より大きなスケールでのArrayListList<T>は同等です。

0
Tyree Jackson