Статический класс С# против структуры для предопределенных строк

StackOverflow https://stackoverflow.com/questions/2223162

Вопрос

Коллега только что создал следующую конструкцию на C# (пример кода упрощен).Его целью было сократить обозначения всех предопределенных строк в остальной части кода.

public struct PredefinedStrings
{
    public const string VeryLongName = "Very Long Name";
    public const string AnotherVeryLongName = "Another Very Long Name";
    public const string TheLastVeryLongName = "The Last Very Long Name";
}

public static void MethodThatUsesTheNames()
{
    Console.WriteLine(PredefinedStrings.VeryLongName);
    Console.WriteLine(PredefinedStrings.AnotherVeryLongName);
    Console.WriteLine(PredefinedStrings.TheLastVeryLongName);
}

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

Каким будет предпочтительный способ сделать это?Пожалуйста, также объясните, почему.

Это было полезно?

Решение

С struct решение, ничто не помешает другому коду сделать new PredefinedStrings(), который не будет сделай что-нибудь плохое, но это семантически запутанно.В случае статического класса компилятор запретит вам создание.И само собой разумеется, что статический класс является предпочтительным способом предоставления констант в Framework.

редактировать добавлю, я сказал, что вторая часть без доказательств - я с тех пор искал и достаточно быстро нашел System.Net.Mime.DispositionTypeNames и System.Net.WebRequestMethods.Http.

Другие советы

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

Помимо static class и struct, почему бы не рассмотреть возможность использования resource файлы для постоянных строк?Доступ к ним можно получить очень легко, так как SomeNamespace.ResourceName.KeyName, и в зависимости от того, где они расположены в вашем проекте, ими можно управлять извне, без перекомпиляции, если это необходимо...

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

У констант есть несколько недостатков:

  • можно использовать только простые типы (строки, числа и т. д.).
  • константы вводятся в ссылающиеся сборки.Если вы перекомпилируете сборку с константами и не перекомпилируете сборку, использующую константы, у вас возникнут проблемы.

Я бы написал ваш код следующим образом (обратите внимание также на рефакторинг переименования):

public static class KnownNames
{
    public static readonly string VeryLong = "Very Long Name";
    public static readonly string AnotherVeryLong = "Another Very Long Name";
    public static readonly string TheLastVeryLong = "The Last Very Long Name";
}

Похоже, вы ищете файл ресурсов (.resx).Это подходящее место для хранения таких строк, а абстракция ваших строк в .resx облегчит локализацию вашего приложения в будущем.Страница MSDN по адресу http://msdn.microsoft.com/en-us/library/1ztca10y.aspx это достойное начало для получения дополнительной информации.

В этом коде нет ничего функционально неправильного.Но стилистически я согласен, что статический класс лучше.Статический класс заявляет, что целью типа является хранение только статических/постоянных данных.

Не забудьте рекомендацию о том, что размер структуры должен составлять около 16 байт.Учитывая 32-битную систему, это 4 ссылки на System.String.Я бы сказал, что вам лучше использовать статический класс, если количество строк увеличится.

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

Вот результаты моего быстрого теста, который включал длину, сравнение, объединение, копирование, indexOf и подстроку.В выпуске .Net 4.0 он запускался без подключенного отладчика.

                                          .Net 3.0  .Net 4.0
static class with static read-only string:  0.217   0.364  seconds
static class with const            string:  0.211   0.361  seconds
struct       with static read-only string:  0.211   0.372  seconds
struct       with const            string:  0.214   0.371  seconds
Properties.Resources               string:  1.173   1.268  seconds

Все они имели примерно одинаковую производительность, за исключением использования файла ресурсов, который медленнее.Хотя Properties.Resources работает медленнее, он не сохраняется в исполняемом файле, поэтому в некоторых случаях это может оказаться более подходящим.Поэтому, на мой взгляд, используйте либо «статический класс», либо Properties.Resources, хранящие строки.

Структур обычно избегают, если они не соответствуют определенным критериям, подробно описанным в разделе этот ответ.

Поскольку ваш коллега не использует его для хранения значения, ему следует использовать класс, а не структуру.

Я думаю, что статика лучше, и вот мои рассуждения.Если этот код живет в какой-то библиотеке, а другой кусок кода потребляет эту библиотеку, если значение константных полей изменится, то не только эту библиотеку нужно будет перекомпилировать (ага), но и придется перекомпилировать код, потребляющий это библиотека тоже.Причина в том, что компиляция вставляет значения констант везде, где вы на них ссылаетесь.Однако если вы используете static, у вас не возникнет этой проблемы, поскольку вы ссылаетесь на поле не ценить.

В своей практике для этой цели мы используем Dictionary<enumNameType, string>.Где enumNameType - это разные типы имен, которые вы можете иметь (в вашем случае)...Этот словарь завернут в статический класс и кэшируется — мы создаем его только при первом использовании, а затем возвращаем тот же объект…

Надеюсь, это будет полезно и вам!

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

Тот простой факт, что вам разрешено создавать новый объект, который должен быть константой, является явным свидетельством плохой практики (обычно).Я говорю «обычно», потому что .NET иногда использует эту концепцию, хотя неясно, почему.

Конечно, вы всегда можете сделать что-то вроде этого:

public class Foo
{
    public struct Bar
    {
        public static double A = 100;

        public Bar(double a)
        {
            A = a;
        }
    }
}

Что технически оправдывает создание Bar;однако нет никакой гарантии, что константа Bar никогда не будет одинаковым (даже в однопоточной среде) и в конечном итоге от него мало пользы.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top