Какой лучший способ реализовать глобальную константу в C #? - PullRequest
10 голосов
/ 09 декабря 2011

У меня есть проект Common, внутри которого я добавил свои публичные константы для QueryStringNames.

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

Есть 3 решения, о которых я знаю, но все они имеют важную проблему.Сборка вызывающей стороны будет содержать копию моей константы, что означает, что если мне придется изменить постоянную величину, мне придется скомпилировать как мою общую сборку, так и сборку вызывающей программы!

1) public const string ConstName = "a value";
2) public readonly string ConstName = "a value";
3) To be stored in a public resource file.

Что будет лучшимподход к определению общедоступных констант в C # помимо их хранения в файле web.config (у которого нет intellisense)?

Ответы [ 7 ]

6 голосов
/ 09 декабря 2011

Если вы думаете, что хотите изменить его и беспокоитесь о необходимости его компиляции, то почему бы не использовать appSettings в файле веб-конфигурации? Вот для чего это. Если вам действительно нужен intellisense, тогда вы можете просто поместить класс в одну из сборок, который считывает значение config и представляет его как свойство для более легкой ссылки. Если это конфиденциальные данные, я бы не поместил их в файл конфигурации, я все равно скомпилировал бы их, поскольку вы не хотите ставить под угрозу свое приложение.

<appSettings>
    <add key="myconstant" value="here's the value!" />
</appSettings>

Вот класс для ссылки на это значение, которое дает вам intellisense, возможность легко изменить его в будущем и без необходимости что-либо перекомпилировать

public class MyAppConfigSettings
{
    public string MyConstant { get; private set; }

    public MyAppConfigSettings()
    {
        MyConstant = ConfigurationManager.AppSettings["myconst"];
    }
}

Возможно, это не решение вашей проблемы, но оно может дать вам другие идеи.

6 голосов
/ 09 декабря 2011

Это зависит.Если это действительно константа, которая не изменится, даже в будущих версиях вашего кода, тогда const хорошо.Иначе идти с полем static readonly.

A const будет встроено в вызывающую сборку, тогда как с static readonly вызывающая сборка содержит только ссылку на поле.Это означает, что const требует перекомпиляции всего зависимого кода при каждом изменении значения, тогда как public readonly использует новое значение даже без перекомпиляции вызывающей сборки.

Если вы хотите сохранить "константу" в конфигурациифайл, но, как и Intellisense, вы можете использовать свойство без открытого сеттера.А затем заполните его из файла конфигурации во время выполнения.Но я бы сказал, что значения конфигурации не должны быть static.Для значений конфигурации я бы использовал какой-то синглтон, предпочтительно вариант IoC, а не вариант Class.Instance.Поэтому я бы просто определил интерфейс, подобный следующему:

interface IMyConfig
{
  string Key{get;}
}

И чтобы классы, которым требуется эта конфигурация, приняли его в качестве параметра конструктора:

public MyClass(IMyConfig config)
{
    ...
}
2 голосов
/ 09 декабря 2011

Я не уверен, полностью ли я понимаю проблему ... вы ищете решение для хранения некоторых глобальных переменных, которые не будут вызывать перекомпиляцию сборок, которые ссылаются на эти глобальные переменные, если вы их измените? Если так, то почему бы не подумать о перестройке вашей архитектуры в соответствии с принципом Inversion of Control ? Подумайте: «Не звоните нам, мы позвоним вам», принцип Голливуда. Если все сборки, которые требуют некоторого const, просто вызывают интерфейс (которым они владеют), который предоставляет свойство со значением, которое им требуется, и тогда у вас есть проект констант, которые реализуют этот интерфейс (путем ссылки на эти проекты и последующей реализации этих интерфейсов) тогда эти проекты никогда не будут нуждаться в перекомпиляции при изменении значения констант.

Я уверен, что вы все равно их знаете, но ознакомились с принципами SOLID , где "D" - это принцип инверсии зависимости (инверсия контроля). Я думаю, учитывая ваши опасения (при условии, что я вас правильно понял), они действительно могут вам помочь.

Пример инверсии управления может быть таким простым:

MyService.dll:

public class MyService
{

    // injected dependency
    public IMyConstants MyConstants { get; set; }

    public MyMethod(){

        // get your query...
        var query = IMyConstants.Query;
    }

}

MyConstants.dll:

public MyConstants : IMyConstants {

    // implementation of query property from the myservices.dll interface
    public string Query { ... }

}

Таким образом, myconstants.dll ссылается на myservice.dll, а не наоборот (то есть myservices не нуждается в перекомпиляции). Затем загрузочный код (чтобы все это настроить и внедрить зависимости) живет в другом месте.

Извините, если я вас неправильно понял, надеюсь, это поможет!

2 голосов
/ 09 декабря 2011

Если вы активируете fxCop (инструмент анализа кода, включенный в дистрибутив Visual Studio), вы можете получить предложение изменить константу на:

public static readonly string ConstName = "a value";

0 голосов
/ 09 декабря 2011

Как уже говорилось, это не тот же сценарий:

  • const: является неизменным и не может быть изменен, кроме как путем перекомпиляции.
  • только для чтения: значение инициализируется в объявлении или в конструкторе и остается только для чтения.

Когда объявление поля включает модификатор readonly, присваивания полям, введенным объявлением, могут происходить только как часть объявления или в конструкторе того же класса

0 голосов
/ 09 декабря 2011

Вы можете использовать объект Cache и определить их в Global.asax

0 голосов
/ 09 декабря 2011

Я предпочитаю второй вариант в большинстве случаев, так как он не вызовет проблем (путем копирования значения в другие сборки). Скорость может быть медленнее, чем у констант, но такая наносекундная скорость довольно незрелая.

...