Как инкапсулировать «глобальные» переменные в C #? / лучшая практика

9

В C #, что является лучшим методом для инкапсуляции переменных, которые мне нужно использовать в нескольких методах? Можно ли просто объявить их в начале моего класса над двумя методами?

Также, если я использую настройки приложения из моего конфигурационного файла, я должен использовать геттер? нравится...

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

Какая лучшая практика?

user1944367
источник
Какова будет цель получения, кроме добавления дополнительного (и, возможно, ненужного) слоя косвенности?
Роберт Харви
4
Геттер намного лучше, чем множественные вызовы, WebConfigurationManager.AppSettingsпотому что его намного легче изменить позже
Daniel Little
@Lavinski: Конечно, если вы думаете, что можете поменять хранилище данных на другое позже. На практике такое случается редко, и вероятность того, что это может произойти для AppSettings, кажется невероятно маленькой.
Роберт Харви
10
Преимущество «getter» заключается в том, что он заставляет intellisense работать - и у вас есть ключевая строка «mySetting» (которая не проверяется компилятором, если она написана правильно) только в одном месте.
Док Браун

Ответы:

5

Это не просто хорошо. Согласно книге «Чистый код», это действительно очень хорошая практика, и дядя Боб действительно поощряет ее. Переменная, используемая многими методами, может показывать высокую степень сплоченности между методами. Кроме того, высокая степень объектных переменных также может указывать на то, что указанный класс следует разделить на две части, поэтому объявление их как объектных переменных может помочь вам найти скрытых кандидатов в класс.

Переменные уровня объекта не являются глобальными переменными, поэтому не бойтесь использовать их, если они должны использоваться разными методами.

Uri
источник
спасибо за вашу помощь, хотя я думаю, что когда вы говорили о сплоченности, вы действительно имели в виду связь.
user1944367
Нет, я имел в виду сплоченность. На уроках разработки программного обеспечения мне также было трудно понять стремление к высокой сплоченности. Обычно мы жаждем слабого сцепления и высокого сцепления. Связь - это физическая вещь, которую мы можем увидеть своими собственными методами. Если класс использует другой класс, то он связан с ним. Если он на самом деле создает экземпляр и объект указанного класса, то он очень похож на него. Тем не менее, сплоченность является более логичной вещью. Высокая сплоченность в классе означает, что его методы принадлежат очень похожей области, даже если они не разделяют какую-либо переменную между ними.
Ури
Различные методы, использующие переменную объекта, не обязательно означают, что они связаны друг с другом. Я мог бы иметь класс Encrypter с переменной пароля char [] и иметь Encrypt (текст строки); и расшифровать (текст строки); методы внутри него. Оба они используют одну и ту же переменную пароля, но между ними нет очевидной связи. Однако вы можете заметить, что они имеют дело с одним и тем же доменом, а именно с шифрованием текста. Насколько я знаю, они имеют высокую степень сплоченности, хотя указанный класс можно разделить на две части. Можно утверждать, что шифрование не относится к области расшифровки.
Ури
4

Инкапсуляция ваших настроек на постоянной основе - отличная идея.

Что я делаю, так это создаю класс настроек либо один статический глобальный класс, либо один или несколько классов экземпляров, которыми я потом буду управлять с помощью внедрения зависимостей. Затем я загружаю все настройки из конфигурации в этот класс при запуске.

Я также написал небольшую библиотеку, которая использует рефлексию, чтобы сделать это еще проще.

Как только мои настройки находятся в моем конфигурационном файле

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

Я делаю статический или экземплярный класс в зависимости от моих потребностей. Для простых приложений с небольшим количеством настроек подходит один статический класс.

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

    public int PagingSize { get; set; }

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

}

Затем с помощью моей библиотеки вызова либо Inflate.Staticили Inflate.Instanceи прохладная вещь я могу использовать любой ключевой источник значения.

using Fire.Configuration;

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

Весь код для этого находится в GitHub на https://github.com/Enexure/Enexure.Fire.Configuration

Есть даже пакет nuget:

PM> Install-Package Enexure.Fire.Configuration

Код для справки:

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 );
                    }
                }
            }
        }
    }
}
Даниэль Литтл
источник