Comment encapsuler des variables "globales" en C #? /meilleur entrainement

9

En C #, quelle est la meilleure pratique pour encapsuler les variables que je dois utiliser dans plusieurs méthodes? Est-il OK de simplement les déclarer en haut de ma classe au-dessus des deux méthodes?

De plus, si j'utilise les paramètres d'application de mon fichier de configuration, dois-je utiliser un getter? comme ça...

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

Quelle est la meilleure pratique?

user1944367
la source
Quel serait le but d'un getter, autre que l'ajout d'une couche d'indirection supplémentaire (et probablement inutile)?
Robert Harvey
4
Un getter est beaucoup mieux que plusieurs appels, WebConfigurationManager.AppSettingscar il est beaucoup plus facile de changer plus tard
Daniel Little
@Lavinski: Bien sûr, si vous pensez que vous pourriez échanger le magasin de données pour un autre plus tard. Dans la pratique, cela se produit rarement et la probabilité que cela se produise pour AppSettings semble extrêmement faible.
Robert Harvey
10
Un "getter" a l'avantage de faire fonctionner intellisense - et vous avez la chaîne de clé "mySetting" (qui n'est pas vérifiée par le compilateur si elle est écrite correctement) en un seul endroit.
Doc Brown

Réponses:

5

Ce n'est pas seulement OK. Selon le livre Clean Code, c'est en fait une très bonne pratique, et l'oncle Bob l'encourage vraiment. Une variable utilisée par de nombreuses méthodes pourrait montrer un haut degré de cohésion entre les méthodes. De plus, un haut degré de variables d'objet pourrait également suggérer que ladite classe devrait être divisée en deux, donc les déclarer en tant que variables d'objet pourrait vous aider à trouver des candidats de classe cachés.

Les variables de niveau objet ne sont pas des variables globales, alors n'ayez pas peur de les utiliser si elles doivent être partagées par différentes méthodes.

Uri
la source
merci pour votre aide, bien que je pense que lorsque vous avez dit cohésion, vous vouliez vraiment dire couplage.
user1944367
Non, je voulais dire cohésion. En cours de génie logiciel, j'ai également eu du mal à comprendre le désir d'une grande cohésion. Habituellement, nous désirons un faible couplage et une forte cohésion. Le couplage est une chose physique que nous pouvons voir sur nos propres méthodes. Si une classe utilise une autre classe, elle y est associée. S'il instancie réellement et objet de ladite classe, alors il est très en couple avec lui. Cependant, la cohésion est plus une chose logique. Une cohésion élevée dans une classe signifie que ses méthodes appartiennent à un domaine très similaire, même si elles ne partagent aucune variable entre elles.
Uri
Diverses méthodes utilisant une variable objet ne signifient pas nécessairement qu'elles sont couplées ensemble. Je pourrais avoir une classe Encrypter avec une variable de mot de passe char [] et avoir Encrypt (texte de chaîne); et Decrypt (texte de chaîne); méthodes à l'intérieur. Les deux utilisent la même variable de mot de passe, mais il n'y a aucun couplage apparent entre eux. Vous pouvez cependant remarquer qu'ils traitent du même domaine, c'est-à-dire le chiffrement de texte. Pour autant que je sache, ils ont un degré élevé de cohésion, bien que ladite classe puisse être divisée en deux. On pourrait faire valoir que le chiffrement n'appartient pas au domaine du déchiffrement.
Uri
4

Encapsuler vos paramètres de manière constante est une excellente idée.

Ce que je fais, c'est créer une classe de paramètres, soit une classe globale statique ou plusieurs classes d'instances que je gérerai ensuite avec l'injection de dépendances. Ensuite, je charge tous les paramètres de configuration dans cette classe au démarrage.

J'ai également écrit une petite bibliothèque qui utilise la réflexion pour rendre cela encore plus facile.

Une fois mes paramètres dans mon fichier de configuration

<?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>

Je crée une classe statique ou d'instance en fonction de mes besoins. Pour les applications simples avec seulement quelques paramètres, une classe statique convient.

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

    public int PagingSize { get; set; }

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

}

Ensuite, en utilisant mon appel de bibliothèque soit Inflate.Staticou, Inflate.Instanceet la chose intéressante est que je peux utiliser n'importe quelle source de valeur clé.

using Fire.Configuration;

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

Tout le code pour cela est dans GitHub à https://github.com/Enexure/Enexure.Fire.Configuration

Il y a même un paquet nuget:

PM> Install-Package Enexure.Fire.Configuration

Code de référence:

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 );
                    }
                }
            }
        }
    }
}
Daniel Little
la source