Uso delle classi statiche come spazi dei nomi

19

Ho visto altri sviluppatori che utilizzano classi statiche come spazi dei nomi

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

Per istanziare le classi interne, sembrerà il seguente

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

La logica è che gli spazi dei nomi possono essere nascosti usando la parola chiave "using". Ma usando le classi statiche, devono essere specificati i nomi delle classi del livello esterno, che preserva in modo efficace gli spazi dei nomi.

Microsoft lo sconsiglia in le linee guida . Personalmente ritengo che influenzi la leggibilità. Quali sono i tuoi pensieri?

    
posta user394128 10.11.2011 - 15:20
fonte

5 risposte

16

L'uso di classi statiche come spazi dei nomi sfida lo scopo di avere spazi dei nomi.

La differenza chiave è qui:

Se definisci CategoryA , CategoryB< come spazi dei nomi e quando l'applicazione utilizza due spazi dei nomi:

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

Qui se CategoryA o CategoryB è una classe statica anziché uno spazio dei nomi, l'utilizzo per l'applicazione è quasi uguale a quello descritto sopra.

Tuttavia, se lo definisci come spazio dei nomi e l'applicazione utilizza solo 1 spazio dei nomi (non include CategoryB ), in questo caso l'applicazione può effettivamente utilizzare i seguenti

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

Ma avevi definito CategoryA come una classe statica la cui sopra non è definita! Uno è costretto a scrivere CategoryA.something ogni volta.

Gli spazi dei nomi dovrebbero essere utilizzati per evitare conflitti di denominazione, mentre la gerarchia delle classi dovrebbe essere utilizzata quando il raggruppamento delle classi ha una certa rilevanza per il modello di sistema.

    
risposta data 10.11.2011 - 15:56
fonte
5

Qualunque cosa stia succedendo qui non è certamente un codice C # idiomatico.

Forse questi altri stanno cercando di implementare il modello del modulo - questo ti permetterebbe di avere funzioni, azioni e così via così come le classi nello 'spazio dei nomi' (vale a dire la classe statica in questo caso)?

    
risposta data 10.11.2011 - 16:13
fonte
4

Prima di tutto, ogni classe dovrebbe essere in uno spazio dei nomi, quindi il tuo esempio sarebbe più simile a:

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

Detto questo, non vedo alcun beneficio di questo tipo di ginnastica in codice quando si può definire un tale spazio dei nomi:

namespace SomeNamespace.CategoryA { ... }

Se forse stai pensando di archiviare alcuni metodi statici a livello di classe superiore, questo potrebbe avere senso, ma non è ancora quello che i creativi di C # hanno in mente, e potrebbe renderlo meno leggibile agli altri - Vorrei sprecare un molto tempo a pensare PERCHÉ avete fatto questo, e pensando se mi manca qualche file sorgente che fornisca spiegazioni.

    
risposta data 10.11.2011 - 15:32
fonte
1

I namespace in Java, JavaScript e .NET non sono completi e permettono solo di memorizzare classi, ma altre cose come costanti o metodi globali, no.

Molti sviluppatori usano i trucchi "classi statiche" o "metodi statici", anche se alcune persone non lo raccomandano.

    
risposta data 11.11.2011 - 01:01
fonte
0

So che questa è una vecchia domanda, ma un motivo molto valido per usare una classe come spazio dei nomi (non statico) è che C # non supporta la definizione di spazi dei nomi parametrici o generici. Ho scritto un post sul blog su questo argomento molto qui: http://tyreejackson.com/generics-net -part5-generic-namespace / .

L'essenza di ciò è che, quando si usano i generici per estendere enormi quantità di codice boilerplate, a volte è necessario condividere più parametri generici tra classi e interfacce correlate. Il modo convenzionale per farlo sarebbe ridefinire i parametri generici, i vincoli e tutto in ogni interfaccia e firma di classe. Nel tempo questo può portare a una proliferazione di parametri e vincoli, senza menzionare costantemente la necessità di qualificare i tipi correlati inoltrando i parametri del tipo da un tipo agli argomenti tipo del tipo correlato.

Utilizzare una classe generica esterna e annidare i tipi correlati all'interno può drasticamente aumentare il codice e semplificarne l'astrazione. Si può quindi derivare la classe dello spazio dei nomi parametrico con un'implementazione concreta che fornisce tutti i dettagli concreti.

Ecco un esempio banale:

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

    }

}

Usato in questo modo:

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

Consuma le derivate in questo modo:

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

    }
}

Il vantaggio di scrivere i tipi in questo modo è stato aggiunto sicurezza del tipo e meno cast di tipi nelle classi astratte. È l'equivalente di ArrayList rispetto a List<T> su una scala più grande.

    
risposta data 05.08.2015 - 22:59
fonte

Leggi altre domande sui tag