Come incapsulare variabili 'globali' in C #? /la migliore pratica


9

In C # qual è la migliore pratica per incapsulare le variabili che devo usare in più metodi? Va bene dichiararli semplicemente in cima alla mia classe sopra i due metodi?

Inoltre, se sto usando le impostazioni dell'app dal mio file di configurazione, dovrei usare un getter? come questo...

private string mySetting{ get { return WebConfigurationManager.AppSettings["mySetting"]; } }

Qual è la migliore pratica?


Quale sarebbe lo scopo di un getter, oltre all'aggiunta di un ulteriore (e probabilmente non necessario) livello di indiretta?
Robert Harvey,

4
Un getter è molto meglio di più chiamate WebConfigurationManager.AppSettingsperché è molto più facile cambiare in seguito
Daniel Little

@Lavinski: Certo, se pensi di poter sostituire l'archivio dati con uno diverso in un secondo momento. In pratica, ciò accade di rado e la probabilità che ciò accada per AppSettings sembra vanificarsi.
Robert Harvey,

10
Un "getter" ha il vantaggio di far funzionare intellisense - e hai la stringa di chiave "mySetting" (che non viene controllata dal compilatore se scritta correttamente) solo in un posto.
Doc Brown,

Risposte:


5

Non va bene. Secondo il libro Clean Code è in realtà una buona pratica e lo zio Bob lo incoraggia davvero. Una variabile utilizzata da molti metodi potrebbe mostrare un alto grado di coesione tra i metodi. Inoltre, un alto grado di variabili oggetto potrebbe anche suggerire che detta classe dovrebbe essere divisa in due, quindi dichiararle come variabili oggetto potrebbe aiutarti a scoprire candidati di classe nascosti.

Le variabili a livello di oggetto non sono variabili globali, quindi non abbiate paura di usarle se devono essere condivise con vari metodi.


grazie per il tuo aiuto, anche se penso che quando hai detto coesione intendevi veramente accoppiare.
user1944367

No, intendevo coesione. Durante la lezione di ingegneria del software ho avuto difficoltà a comprendere il desiderio di alta coesione. Di solito desideriamo poco accoppiamento e alta coesione. L'accoppiamento è una cosa fisica che possiamo vedere con i nostri metodi. Se una classe usa un'altra classe, allora è accoppiata ad essa. Se in realtà crea un'istanza e oggetto di detta classe, allora è molto coppia. Tuttavia, la coesione è più una cosa logica. Alta coesione in una classe significa che i suoi metodi appartengono a un dominio molto simile, anche se non condividono alcuna variabile tra di loro.
Uri,

Vari metodi che utilizzano una variabile oggetto non significano necessariamente che siano accoppiati insieme. Potrei avere una classe Encrypter con una variabile password char [] e avere Encrypt (testo stringa); e Decrypt (testo stringa); metodi al suo interno. Entrambi usano la stessa variabile di password, ma non esiste alcun accoppiamento apparente tra di loro. Tuttavia, potresti notare che hanno a che fare con lo stesso dominio e cioè con la crittografia del testo. Per quanto ne so, hanno un alto grado di coesione, sebbene detta classe possa essere divisa in due. Si potrebbe sostenere che la crittografia non appartiene al dominio della decrittazione.
Uri,

4

Incapsulare le impostazioni in modo costante è un'ottima idea.

Quello che faccio è creare una classe di impostazioni una globale statica o più classi di istanza che gestirò con l'iniezione di dipendenza. Quindi carico tutte le impostazioni dalla configurazione in quella classe all'avvio.

Ho anche scritto una piccola biblioteca che utilizza la riflessione per renderlo ancora più semplice.

Una volta che le mie impostazioni sono nel mio file di configurazione

<?xml version="1.0" encoding="utf-8" ?>
<configuration>   
    <appSettings>
        <add key="Domain" value="example.com" />
        <add key="PagingSize" value="30" />
        <add key="Invalid.C#.Identifier" value="test" />
    </appSettings>
</configuration>

Faccio una classe statica o di istanza a seconda delle mie esigenze. Per applicazioni semplici con poche impostazioni, una classe statica va bene.

private static class Settings
{
    public string Domain { get; set; }

    public int PagingSize { get; set; }

    [Named("Invalid.C#.Identifier")]
    public string ICID { get; set; }

}

Quindi usando la mia chiamata in libreria o Inflate.Statico Inflate.Instancee il bello è che posso usare qualsiasi fonte di valore chiave.

using Fire.Configuration;

Inflate.Static( typeof(Settings), x => ConfigurationManager.AppSettings[x] );

Tutto il codice per questo è in GitHub all'indirizzo https://github.com/Enexure/Enexure.Fire.Configuration

C'è anche un pacchetto nuget:

PM> Install-Package Enexure.Fire.Configuration

Codice di riferimento:

using System;
using System.Linq;
using System.Reflection;
using Fire.Extensions;

namespace Fire.Configuration
{
    public static class Inflate
    {
        public static void Static( Type type, Func<string, string> dictionary )
        {
            Fill( null, type, dictionary );
        }

        public static void Instance( object instance, Func<string, string> dictionary )
        {
            Fill( instance, instance.GetType(), dictionary );
        }


        private static void Fill( object instance, Type type, Func<string, string> dictionary ) 
        {

            PropertyInfo[] properties;
            if (instance == null) {

                // Static
                properties = type.GetProperties( BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly );
            } else {

                // Instance
                properties = type.GetProperties( BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly );
            }

            // Get app settings and convert
            foreach (PropertyInfo property in properties) {
                var attributes = property.GetCustomAttributes( true );
                if (!attributes.Any( x => x is Ignore )) {

                    var named = attributes.FirstOrDefault( x => x is Named ) as Named;

                    var value = dictionary((named != null)? named.Name : property.Name);

                    object result;
                    if (ExtendConversion.ConvertTo(value, property.PropertyType, out result)) {
                        property.SetValue( instance, result, null );
                    }
                }
            }
        }
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.