Menggunakan kelas statis sebagai ruang nama

21

Saya telah melihat pengembang lain menggunakan kelas statis sebagai ruang nama

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() { }
    }
}

Untuk membuat instance kelas dalam, itu akan terlihat seperti berikut

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

Alasannya adalah ruang nama dapat disembunyikan dengan menggunakan kata kunci "using". Tetapi dengan menggunakan kelas statis, nama-nama kelas lapisan luar harus ditentukan, yang secara efektif mempertahankan ruang nama.

Microsoft menyarankan agar hal itu tidak ada dalam pedoman . Saya pribadi berpikir itu berdampak pada keterbacaan. Apa yang kamu pikirkan?

pengguna394128
sumber
1
Terserah pelaksana apakah mereka membutuhkan ruang nama yang ada dalam implementasi. Mengapa Anda memaksakan penggunaan ruang nama (dan ruang nama palsu pada saat itu) pada mereka?
Craige
Mungkin untuk tujuan pengelompokan? Seperti ada banyak sub kelas dan dengan mengelompokkan sub kelas ke kelas statis. Itu membuat kehebatannya jelas?
user394128
Akankah menempatkan sub-kelas dalam sub-namespace tidak juga memperjelas maksudnya? Juga, ini adalah jenis masalah yang diselesaikan oleh dokumentasi.
Craige

Jawaban:

16

Menggunakan kelas statis sebagai ruang nama menentang tujuan memiliki ruang nama.

Perbedaan utama ada di sini:

Jika Anda mendefinisikan CategoryA, CategoryB<sebagai ruang nama, dan saat aplikasi menggunakan dua ruang nama:

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

Di sini jika CategoryAatau CategoryBadalah kelas statis daripada namespace, penggunaan aplikasi hampir sama seperti yang dijelaskan di atas.

Namun, jika Anda mendefinisikannya sebagai namespace dan aplikasi hanya menggunakan 1 namespace (tidak termasuk CategoryB), dalam hal ini aplikasi dapat benar-benar menggunakan mengikuti

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

Tetapi apakah Anda mendefinisikan CategoryAsebagai kelas statis di atas tidak terdefinisi! Seseorang dipaksa untuk menulis CategoryA.somethingsetiap saat.

Namespaces harus digunakan untuk menghindari konflik penamaan sedangkan hirarki kelas harus digunakan ketika pengelompokan kelas memiliki beberapa relevansi dengan model sistem.

Dipan Mehta
sumber
Juga, jika seseorang ingin tidak menggunakan ruang nama, bahkan menggunakan kelas kaleng: using Item1 = CategoryA.Item1(saya pikir itu berfungsi untuk kelas bersarang seperti halnya ruang nama)
George Duckett
1
Dalam C ++, ADL tidak bekerja dengan ruang lingkup kelas; ini bekerja dengan lingkup namespace. Jadi di C ++, namespace tidak hanya pilihan alami, tetapi juga pilihan yang benar dan idiomatis .
Nawaz
Saya pikir itu niat OP untuk menghindari menyembunyikan namespace dengan menggunakan kata kunci. Dia ingin memaksa pengguna untuk menulisnya setiap saat. Mungkin namespace-nya sepertivar s = new HideMe.MyPhoneNumberIs12345678.TheRealUsefulClass()
Gqqnbig
5

Apa pun yang terjadi di sini tentu bukan kode C # idiomatik.

Mungkin yang lain ini mencoba menerapkan pola modul - ini akan membiarkan Anda memiliki fungsi, tindakan dan sebagainya serta kelas di 'namespace' (yaitu kelas statis dalam kasus ini)?

FinnNk
sumber
Saya setuju, terlihat aneh.
marko
4

Pertama-tama, setiap kelas harus dalam namespace, jadi contoh Anda sebenarnya akan lebih seperti:

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

Yang mengatakan, saya tidak melihat manfaat dari senam kode semacam ini ketika Anda bisa mendefinisikan namespace seperti itu:

namespace SomeNamespace.CategoryA { ... }

Jika Anda mungkin suatu hari berpikir untuk menyimpan beberapa metode statis pada tingkat kelas atas, ini bisa masuk akal, tetapi masih bukan apa yang ada dalam pikiran pencipta C #, dan mungkin membuatnya kurang mudah dibaca oleh orang lain - saya akan membuang banyak waktu berpikir MENGAPA Anda melakukan ini, dan berpikir jika saya kehilangan beberapa file sumber yang akan memberikan penjelasan.

zmilojko
sumber
Jadi mengapa enum merupakan pengecualian terhadap aturan ?
sq33G
Itu adalah pertanyaan yang berbeda :) Tapi saya masih tidak akan mendefinisikan kelas statis hanya untuk mendefinisikan enum di dalamnya.
zmilojko
1

Namespace di Java, JavaScript dan .NET terkait tidak lengkap, dan hanya memungkinkan untuk menyimpan kelas, tetapi hal-hal lain seperti konstanta atau metode global, tidak.

Banyak pengembang menggunakan trik "kelas statis" atau "metode statis", bahkan jika beberapa orang tidak merekomendasikannya.

umlcat
sumber
0

Saya tahu bahwa ini adalah pertanyaan lama, tetapi satu alasan yang sangat valid untuk menggunakan kelas sebagai namespace (yang tidak statis pada saat itu) adalah bahwa C # tidak mendukung definisi ruang nama parametrik atau generik. Saya telah menulis posting blog tentang topik ini di sini: http://tyreejackson.com/generics-net-part5-generic-namespaces/ .

Inti dari itu adalah, ketika menggunakan obat generik untuk abstrak petak besar kode boilerplate, kadang-kadang diperlukan untuk berbagi beberapa parameter generik antara kelas dan antarmuka terkait. Cara konvensional untuk melakukan ini adalah dengan mendefinisikan kembali parameter generik, batasan dan semua di setiap antarmuka dan kelas tanda tangan. Seiring waktu hal ini dapat menyebabkan proliferasi parameter dan kendala belum lagi harus terus-menerus memenuhi syarat untuk jenis terkait dengan meneruskan parameter jenis dari satu jenis ke jenis argumen dari jenis terkait.

Menggunakan kelas Generic luar dan menumpuk jenis terkait di dalamnya dapat secara dramatis MENINGGALKAN kode dan menyederhanakan abstraksinya. Seseorang kemudian dapat menurunkan kelas namespace parametrik dengan implementasi konkret yang memasok semua detail konkret.

Berikut ini adalah contoh sepele:

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

    }

}

Digunakan seperti ini:

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 {}
}

Konsumsi turunannya seperti ini:

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

    }
}

Manfaat menulis tipe dengan cara ini adalah menambahkan keamanan tipe dan mengurangi casting tipe dalam kelas abstrak. Ini setara dengan ArrayListvs List<T>pada skala yang lebih besar.

Tyree Jackson
sumber