静的クラスを名前空間として使用する


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

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


1
実装に存在する名前空間が必要かどうかは、実装者次第です。名前空間(およびその偽の名前空間)の使用をなぜ強制するのですか?
クレイジュ

グループ化の目的ですか?多くのサブクラスがあるように、サブクラスを静的クラスにグループ化することによって。それは意図を明確にしますか?
user394128

サブクラスをサブ名前空間に配置しても、意図が明確にならないでしょうか?また、これはドキュメントによって解決される問題のタイプです。
クレイジュ

回答:


16

名前空間として静的クラスを使用すると、名前空間を持つという目的に反します。

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

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

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毎回書き込みを強制されます。

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


また、誰かが名前空間を使用したくない場合は、クラスを使用してもできます:(using Item1 = CategoryA.Item1ネストされたクラスでも名前空間と同じように動作すると思います)
ジョージデュケット

1
C ++では、ADLはクラススコープでは機能しません。名前空間スコープで動作します。そのため、C ++では、名前空間は自然な選択であるだけでなく、正確慣用的な選択でもあります。
ナワズ

usingキーワードによって名前空間を隠すことを避けるのはOPの意図だと思います。彼はユーザーに毎回それを書くように強制したい。たぶん彼の名前空間はvar s = new HideMe.MyPhoneNumberIs12345678.TheRealUsefulClass()
-Gqqnbig

5

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

これらの他の人がモジュールパターンを実装しようとしているのかもしれません-これにより、「名前空間」のクラス(この場合は静的クラス)と同様に、関数、アクションなどを使用できますか?


私は同意する、奇妙に見える。
マルコ

4

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

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

そうは言っても、そのような名前空間を同様に定義できる場合、この種のコード体操の利点はありません。

namespace SomeNamespace.CategoryA { ... }

いつか上位クラスレベルでいくつかの静的メソッドを保存することを考えている場合、これは理にかなっているかもしれませんが、それでもC#作成者が念頭に置いているものではなく、他の人に読みにくくするかもしれません-多くの時間を無駄にしますなぜあなたがこれをしたのかを考え、説明を提供するソースファイルが欠けているかどうかを考えます。


では、なぜenums はルール例外なのですか?
sq33G

それは別の質問です:)しかし、私はまだ列挙型を定義するためだけに静的クラスを定義しません。
zmilojko

1

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

多くの開発者は、「静的クラス」または「静的メソッド」のトリックを使用しています(一部の人が推奨していなくても)。


0

私はこれが古い質問であることを知っていますが、クラスを名前空間として使用する非常に正当な理由(その時点で非静的なもの)は、C#がパラメトリックまたはジェネリック名前空間の定義をサポートしていないことです。http://tyreejackson.com/generics-net-part5-generic-namespaces/でこのトピックに関するブログ投稿を作成しました。

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

外側の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>

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.