Como encapsular variáveis ​​'globais' em C #? /Melhor prática

9

Em C #, qual é a melhor prática para encapsular variáveis ​​que preciso usar em vários métodos? Tudo bem simplesmente declará-los no topo da minha classe acima dos dois métodos?

Além disso, se eu estiver usando as configurações do aplicativo no meu arquivo de configuração, devo usar um getter? como isso...

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

Qual é a melhor prática?

user1944367
fonte
Qual seria o objetivo de um getter, além de adicionar uma camada adicional (e provavelmente desnecessária) de indireção?
Robert Harvey
4
Um getter é muito melhor do que várias chamadas para WebConfigurationManager.AppSettingsporque é muito mais fáceis de mudar mais tarde
Daniel Little
@Lavinski: Claro, se você acha que pode trocar o repositório de dados por outro posteriormente. Na prática, isso raramente acontece e a probabilidade de que isso aconteça no AppSettings parece muito pequena.
Robert Harvey
10
Um "getter" tem a vantagem de fazer o intellisense funcionar - e você tem a cadeia de caracteres "mySetting" (que não é verificada pelo compilador se for escrita corretamente) apenas em um local.
Doc Brown

Respostas:

5

Não está tudo bem. De acordo com o livro Clean Code, na verdade, é uma prática muito boa, e o tio Bob realmente a incentiva. Uma variável usada por muitos métodos pode mostrar um alto grau de coesão entre os métodos. Além disso, um alto grau de variáveis ​​de objeto também pode sugerir que a referida classe deve ser dividida em duas, portanto, declará-las como variáveis ​​de objeto pode ajudá-lo a descobrir candidatos a classes ocultas.

As variáveis ​​no nível do objeto não são variáveis ​​globais, portanto, não tenha medo de usá-las se elas devem ser compartilhadas por vários métodos.

Uri
fonte
obrigado por sua ajuda, embora eu pense que quando você disse coesão você realmente quis dizer acoplamento.
usar o seguinte comando
Não, eu quis dizer coesão. Na aula de Engenharia de Software, também tive dificuldade em entender o desejo de alta coesão. Geralmente desejamos baixo acoplamento e alta coesão. O acoplamento é uma coisa física que podemos ver em nossos próprios métodos. Se uma classe usa outra classe, ela é acoplada a ela. Se realmente instancia e objeto da referida classe, então é muito parecido. No entanto, a coesão é mais uma coisa lógica. Coesão alta em uma classe significa que seus métodos pertencem a um domínio muito semelhante, mesmo que eles não compartilhem nenhuma variável entre eles.
Uri
Vários métodos usando uma variável de objeto não necessariamente significam que eles são acoplados. Eu poderia ter uma classe Encrypter com uma variável de senha char [] e ter Criptografar (texto da string); e Decifrar (texto da string); métodos dentro dele. Ambos usam a mesma variável de senha, mas não há acoplamento aparente entre eles. Você pode notar, no entanto, que eles lidam com o mesmo domínio, ou seja, criptografia de texto. Tanto quanto eu sei, eles têm um alto grau de coesão, embora a referida classe possa ser dividida em duas. Alguém poderia argumentar que a criptografia não pertence ao domínio da descriptografia.
Uri
4

Encapsular suas configurações de maneira constante é uma ótima idéia.

O que faço é criar uma classe de configurações, uma global estática, uma ou várias instâncias, que gerenciarei com injeção de dependência. Em seguida, carrego todas as definições de configuração nessa classe na inicialização.

Também escrevi uma pequena biblioteca que faz uso da reflexão para tornar isso ainda mais fácil.

Quando minhas configurações estiverem no meu arquivo de configuração

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

Eu faço uma classe estática ou de instância, dependendo das minhas necessidades. Para aplicativos simples com apenas algumas configurações, uma classe estática é boa.

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

    public int PagingSize { get; set; }

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

}

Então, usando minha chamada de biblioteca ou Inflate.Staticou, Inflate.Instanceo interessante é que posso usar qualquer fonte de valor-chave.

using Fire.Configuration;

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

Todo o código para isso está no GitHub em https://github.com/Enexure/Enexure.Fire.Configuration

Existe até um pacote de pepitas:

PM> Enexure.Fire.Configuration do pacote de instalação

Código de referência:

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
fonte