Jaki jest najlepszy sposób przechowywania grupy stałych, których używa mój program? [Zamknięte]

97

Mam różne stałe, których mój program używa ... string, int's, double' s, itd ... Jaki jest najlepszy sposób ich przechowywania? Wydaje mi się, że nie chcę Enum, ponieważ dane nie są tego samego typu i chcę ręcznie ustawić każdą wartość. Czy powinienem po prostu przechowywać je wszystkie w pustej klasie? Czy jest jakiś lepszy sposób?

Mateusz
źródło
18
Jak tylko chcesz - tak tego potrzebujesz.
San Jacinto

Odpowiedzi:

135

Prawdopodobnie mógłbyś mieć je w klasie statycznej ze statycznymi właściwościami tylko do odczytu.

public static class Routes
{
    public static string SignUp => "signup";
}
Daniel A. White
źródło
23
+1, ale jeszcze lepiej, jeśli możesz je pobrać z pliku zasobów w celu lokalizacji.
Joel Coehoorn
17
Wydaje się trochę rozwlekłe - dlaczego nie statyczne ciągi tylko do odczytu?
emptyset
6
Dlaczego tylko do odczytu, a nie const? Nie ustawiasz wartości w czasie wykonywania, więc nie ma potrzeby, aby były one tylko do odczytu.
Philip Wallace
91
Problem z const polega na tym, że wszystkie zespoły skompilowane względem stałych otrzymują lokalne kopie tych stałych, gdy same są kompilowane; więc jeśli zmienisz wartość, musisz również ponownie skompilować wszystkie zestawy zależne od zestawu definiującego stałe - dlatego często bezpieczniej jest skorzystać z trasy tylko do odczytu. Właściwości zamiast publicznych wartości statycznych zapewniają elastyczność dodawania w przyszłości pewnej logiki programowania, jeśli będzie to potrzebne (tj. Odczyt z lokalizacji) bez zmiany interfejsu na wartości stałe.
cfeduke
11
Jako adwokat diabła muszę zaznaczyć, że zaletą const jest to, że można go używać w przypadkach przełączników.
arviman
27

IMO używające klasy pełnej stałych jest dobre dla stałych. Jeśli będą się zmieniać od czasu do czasu, polecam zamiast tego użycie AppSettings w konfiguracji i klasie ConfigurationManager.

Kiedy mam „stałe”, które są faktycznie pobierane z AppSettings lub podobnych, nadal będę mieć klasę „constants”, która zawija odczyt z menedżera konfiguracji. Zawsze bardziej sensowne jest mieć, Constants.SomeModule.Settingzamiast uciekać się bezpośrednio do ConfigurationManager.AppSettings["SomeModule/Setting"]dowolnego miejsca, które chce skonsumować tę wartość ustawienia.

Dodatkowe punkty za tę konfigurację, ponieważ SomeModuleprawdopodobnie byłaby to klasa zagnieżdżona w pliku Constants, można z łatwością użyć funkcji Dependency Injection, aby wstrzyknąć SomeModulebezpośrednio do klas, które od niej zależą. Możesz nawet wyodrębnić interfejs na wierzchu, SomeModulea następnie utworzyć zależność od ISomeModuleConfigurationużywanego kodu, co pozwoli ci oddzielić zależność od plików Constants, a nawet potencjalnie ułatwi testowanie, zwłaszcza jeśli te ustawienia pochodzą z AppSettings i zmieniasz je za pomocą transformacji konfiguracji, ponieważ ustawienia są specyficzne dla środowiska.

Chris Marisic
źródło
1
Wystarczy dodać do tego: powodem jest to, że podczas budowania stałe używane z innych zestawów nie są aktualizowane. Oznacza to, że jeśli masz AssemblyA, a AssemblyB i B używa stałej z A, wartość jest kopiowana, a nie odwoływana, więc ponowne budowanie A nie zaktualizuje B. Może to prowadzić do dziwnych błędów.
Camilo Martin
1
@CamiloMartin na wiele sposobów radzenia sobie z tym, twoje „stałe” mogą po prostu statyczne tylko do odczytu, aby tego uniknąć, lub jak powiedziałem, jeśli zmieniają się więcej niż raz na niebieskim księżycu, aby użyć ConfigurationManager.
Chris Marisic,
Tak, właśnie mówiłem, że nie tylko dlatego, że jest to konwencja, że ​​należy używać tylko odczytu statycznego, ale dlatego, że w rzeczywistości może to być źródłem nieporozumień. Alternatywą dla ConfigurationManager są również pliki zasobów - wystarczy dodać kolejny plik zasobów z kodem języka w nazwie, a kod zostanie natychmiast zlokalizowany.
Camilo Martin
problem polega na tym, że kiedy odwołujesz się do tego zestawu z innych zestawów, musisz skopiować wartości do ich plików konfiguracyjnych
symbiont
@symbiont możesz zamiast tego osadzić pliki konfiguracyjne i odczytać je z manifestu, jeśli chcesz, aby udostępniać je jako składnik innej firmy
Chris Marisic
19

Lubię robić następujące rzeczy (ale pamiętaj, aby przeczytać do końca, aby użyć odpowiednich typów stałych ):

internal static class ColumnKeys
{
    internal const string Date = "Date";
    internal const string Value = "Value";
    ...
}

Przeczytaj to, aby dowiedzieć się, dlaczego constmoże nie być tym, czego chcesz. Możliwe typy stałych to:

  • constpola. Nie używaj między zestawami ( publiclub protected), jeśli wartość może się zmienić w przyszłości, ponieważ wartość zostanie zakodowana na stałe w czasie kompilacji w tych innych zestawach. Jeśli zmienisz wartość, stara wartość będzie używana przez inne zestawy, dopóki nie zostaną ponownie skompilowane.
  • static readonly pola
  • static nieruchomość bez set
Marcel Gosselin
źródło
1
Dlaczego tylko do odczytu, jeśli jest używany w wielu zestawach?
Philip Wallace
Dlaczego static readonly działa lepiej z wieloma zestawami niż const?
Matthew
15
Wartości const są kopiowane z zestawu źródłowego do skompilowanego kodu. Oznacza to, że jeśli musisz zmienić wartość const, wszystkie zespoły zależne MUSZĄ zostać ponownie skompilowane do nowej wersji. Bezpieczniejsze i wygodniejsze w użyciu statyczne tylko do odczytu.
cfeduke
6
Zaletą
11

To jest najlepszy sposób IMO. Nie ma potrzeby korzystania z właściwości lub tylko do odczytu:

public static class Constants
{
   public const string SomeConstant = "Some value";
}
Philip Wallace
źródło
9
Jeśli zamierzasz używać const, ujawnij jako tylko wewnętrzną. Nie upubliczniaj const (nawet jeśli uważasz, że twoje zestawy nie będą używane poza organizacją). Właściwości zapewniają również elastyczność programową do przyszłej rozbudowy bez konieczności ponownego definiowania interfejsu.
cfeduke
4

Odpowiednia jest pusta klasa statyczna. Rozważ użycie kilku klas, aby uzyskać dobre grupy powiązanych stałych, a nie jeden gigantyczny plik Globals.cs.

Dodatkowo, dla niektórych stałych int, rozważ notację:

[Flags]
enum Foo
{
}

Ponieważ pozwala to traktować wartości jak flagi .

pusty zestaw
źródło
„Rozważ użycie kilku klas, aby otrzymać dobre grupy powiązanych stałych, a nie jeden gigantyczny plik Globals.cs”. Uważam, że to najlepsza rekomendacja, czy nie ma wokół tego pewnych wzorców projektowych? Nie znam nikogo z nazwiska, prawda?
greg
3

Kolejny głos za użyciem web.config lub app.config. Pliki konfiguracyjne są dobrym miejscem na stałe, takie jak parametry połączenia, itp. Wolę nie patrzeć na źródło, aby przeglądać lub modyfikować tego typu rzeczy. Klasa statyczna, która odczytuje te stałe z pliku .config, może być dobrym kompromisem, ponieważ umożliwi aplikacji dostęp do tych zasobów tak, jakby były zdefiniowane w kodzie, ale nadal zapewnia elastyczność polegającą na umieszczeniu ich w łatwo przeglądalnym / edytowalnym przestrzeń.

3Dave
źródło
2
Ciąg połączenia nie jest stałą, jest to ustawienie. Możliwe, że OP naprawdę oznacza również ustawienia, a nie stałe, ale nie widzę na to żadnych dowodów.
Jon Skeet
Pozwolę sobie być innego zdania. Literały łańcuchowe są z definicji stałymi. Zmiana ciągu w pliku konfiguracyjnym jest mniej więcej równoważna zmianie w kodzie i ponownej kompilacji; czy to by nie było stałe? Nie sądzę.
Zapisz
2
@David - Nieprawda. Kompilator nie dba o to, jaką wartość masz w pliku konfiguracyjnym - jest to odczytywane w czasie wykonywania.
Philip Wallace
@PhilipW Rozumiem to. Chodziło mi o to, że (w odpowiedzi na komentarz Jona Skeeta) określony ciąg połączenia jest stałą, tak jak wszystkie literały ciągów. Fakt, że „stałą” można zmienić - na przykład poprzez modyfikację pliku konfiguracyjnego i nakłonienie aplikacji do ściągnięcia nowej wartości ze wspomnianego pliku konfiguracyjnego lub przez zmianę literału w kodzie, który wymagałby ponownej kompilacji / wdrożenia - nie uczyń z niego „ustawienie”. Sam ciąg jest stały niezależnie od jego pojemnika. Rozumiem i zgadzam się z twoim punktem widzenia - po prostu nie o tym mówiłem.
Zapisz
1
Z mojego doświadczenia wynika, że ​​w pewnym momencie w nieprzewidzianej przyszłości wasza „stała” wartość będzie musiała ulec zmianie, nawet jeśli myśleliście, że nigdy nie zmieni się ona za milion lat. Myślę, że jest to o wiele łatwiejsze do zrobienia w pliku .config niż zmiana kodu źródłowego. W końcu wszystko staje się scenerią.
NinjaBomb
1

Tak, static classdo przechowywania stałych wystarczyłoby, z wyjątkiem stałych powiązanych z określonymi typami.

bruno conde
źródło
to jest dokładnie to, co próbuję zrobić. chcę, żeby pojawili się jako członkowie klasy, dla której są. ale nie chcę dodawać ich do zajęć, ponieważ stałe różnią się w zależności od firmy, dla której wykonuję pracę. nie znalazłem jeszcze nic o stałych rozszerzeniach lub właściwościach. ale mogę zrezygnować z tego pomysłu, ponieważ nie chcę, aby pojawiali się jako członkowie podczas serializacji tych klas
symbiont
0

Jeśli te stałe są odwołaniami do usług lub przełącznikami, które wpływają na zachowanie aplikacji, ustawiłbym je jako ustawienia użytkownika aplikacji. W ten sposób, jeśli trzeba je zmienić, nie trzeba ich ponownie kompilować i nadal można się do nich odwoływać za pośrednictwem statycznej klasy właściwości.

Properties.Settings.Default.ServiceRef
Aaron
źródło
0

Sugerowałbym klasę statyczną ze statycznym tylko do odczytu. Poniżej znajdziesz fragment kodu:

  public static class CachedKeysManager
    {
        public static readonly string DistributorList = "distributorList";
    }
KAPIL SHARMA
źródło