Wie kann eine Gruppe von Konstanten, die mein Programm verwendet, am besten gespeichert werden? [geschlossen]

97

Ich habe verschiedene Konstanten, die mein Programm verwendet ... string's, int' s, double's, etc ... Was ist der beste Weg, um sie zu speichern? Ich glaube nicht, dass ich eine möchte Enum, da die Daten nicht alle vom gleichen Typ sind und ich jeden Wert manuell festlegen möchte. Soll ich sie alle in einer leeren Klasse aufbewahren? Oder gibt es einen besseren Weg?

Matthew
quelle
18
Wie auch immer Sie es wollen - so brauchen Sie es.
San Jacinto

Antworten:

134

Sie könnten sie wahrscheinlich in einer statischen Klasse mit statischen schreibgeschützten Eigenschaften haben.

public static class Routes
{
    public static string SignUp => "signup";
}
Daniel A. White
quelle
23
+1, aber noch besser, wenn Sie diese zur Lokalisierung aus einer Ressourcendatei abrufen können.
Joel Coehoorn
17
Scheint ein bisschen wortreich - warum nicht statische schreibgeschützte Zeichenfolgen?
Emptyset
6
Warum schreibgeschützt und nicht const? Sie legen den Wert nicht zur Laufzeit fest, sodass sie nicht schreibgeschützt sein müssen.
Philip Wallace
91
Das Problem mit const ist, dass alle gegen consts kompilierten Assemblys lokale Kopien dieser consts erhalten, wenn sie selbst kompiliert werden. Wenn Sie also einen Wert ändern, müssen Sie auch alle Assemblys neu kompilieren, abhängig von Ihrer Assembly, die die Konstanten definiert. Daher ist es oft sicherer, den schreibgeschützten Weg zu gehen. Eigenschaften anstelle von öffentlichen statischen Werten bieten Ihnen die Flexibilität, in Zukunft Programmierlogik hinzuzufügen, wenn Sie diese benötigen (dh aus der Lokalisierung lesen), ohne die Schnittstelle auf Ihre konstanten Werte zu ändern.
cfeduke
11
Als Anwalt des Teufels muss ich darauf hinweisen, dass der Vorteil von const darin besteht, dass Sie es in Switch-Fällen verwenden können.
Arviman
27

IMO mit einer Klasse voller Konstanten ist für Konstanten in Ordnung. Wenn sie sich gelegentlich ändern, empfehle ich, stattdessen AppSettings in Ihrer Konfiguration und in der ConfigurationManager-Klasse zu verwenden.

Wenn ich "Konstanten" habe, die tatsächlich aus AppSettings oder ähnlichem abgerufen werden, habe ich immer noch eine "Konstanten" -Klasse, die das Lesen vom Konfigurationsmanager umschließt. Es ist immer sinnvoller zu haben, Constants.SomeModule.Settinganstatt direkt ConfigurationManager.AppSettings["SomeModule/Setting"]auf einen Ort zurückgreifen zu müssen, der diesen Einstellwert konsumieren möchte.

Bonuspunkte für dieses Setup, da SomeModulees sich wahrscheinlich um eine verschachtelte Klasse in der Konstantendatei handelt, können Sie Dependency Injection problemlos verwenden, um entweder SomeModuledirekt in davon abhängige Klassen zu injizieren . Sie können auch eine Schnittstelle darüber extrahieren SomeModuleund dann eine Abhängigkeit von ISomeModuleConfigurationIhrem konsumierenden Code erstellen. Auf diese Weise können Sie die Abhängigkeit von den Konstantendateien entkoppeln und das Testen möglicherweise sogar vereinfachen, insbesondere wenn diese Einstellungen von AppSettings und stammen Sie ändern sie mithilfe von Konfigurationstransformationen, da die Einstellungen umgebungsspezifisch sind.

Chris Marisic
quelle
1
Nur um dies hinzuzufügen: Der Grund dafür ist, dass beim Erstellen Konstanten, die von anderen Assemblys verwendet werden, nicht aktualisiert werden. Dies bedeutet, dass wenn Sie AssemblyA und AssemblyB haben und B eine Konstante von A verwendet, der Wert kopiert und nicht referenziert wird, sodass beim erneuten Erstellen von A B nicht aktualisiert wird. Dies kann zu seltsamen Fehlern führen.
Camilo Martin
1
@CamiloMartin viele Möglichkeiten, damit umzugehen, Ihre "Konstanten" könnten nur statische Readonlys sein, um dies zu vermeiden, oder wie gesagt, wenn sie sich in einem blauen Mond mehr als einmal ändern, um den ConfigurationManager zu verwenden.
Chris Marisic
Ja, ich habe nur gesagt, dass es nicht nur eine Konvention ist, dass Sie statisch schreibgeschützt verwenden sollten, sondern dass dies tatsächlich zu Verwirrung führen kann. Eine Alternative zu ConfigurationManager sind Ressourcendateien. Sie müssen lediglich eine weitere Ressourcendatei mit einem Sprachcode im Namen hinzufügen, und Ihr Code wird sofort lokalisiert.
Camilo Martin
Das Problem ist, dass Sie, wenn Sie auf diese Assembly von anderen Assemblys verweisen, die Werte in ihre Konfigurationsdateien kopieren müssten
Symbiont
@symbiont Sie könnten die Konfigurationsdateien einbetten und sie stattdessen aus dem Manifest lesen, wenn Sie möchten, um sie als Drittanbieter-Komponente zu
teilen
19

Was ich gerne mache, ist Folgendes (aber lesen Sie es unbedingt bis zum Ende durch, um den richtigen Konstantentyp zu verwenden ):

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

Lesen Sie dies, um zu erfahren, warum Sie constmöglicherweise nicht das sind, was Sie wollen. Mögliche Arten von Konstanten sind:

  • constFelder. Verwenden Sie nicht über Baugruppen ( publicoder protected) , wenn der Wert könnte sich in Zukunft ändern , da der Wert zum Zeitpunkt der Kompilierung in den anderen Baugruppen fest einprogrammiert werden. Wenn Sie den Wert ändern, wird der alte Wert von den anderen Assemblys verwendet, bis sie neu kompiliert werden.
  • static readonly Felder
  • static Eigentum ohne set
Marcel Gosselin
quelle
1
Warum schreibgeschützt, wenn es für mehrere Baugruppen verwendet wird?
Philip Wallace
Warum funktioniert statisches Readonly bei mehreren Assemblys besser als const?
Matthew
15
Konstantenwerte werden von der Quellassembly in den kompilierten Code kopiert. Das heißt, wenn Sie einen const-Wert ändern müssen, MÜSSEN alle abhängigen Assemblys mit der neuen Version neu kompiliert werden. Sicherer und bequemer, statische Readonlys zu verwenden.
cfeduke
6
Der
Vorteil
11

Dies ist der beste Weg IMO. Keine Notwendigkeit für Eigenschaften oder schreibgeschützt:

public static class Constants
{
   public const string SomeConstant = "Some value";
}
Philip Wallace
quelle
9
Wenn Sie const verwenden möchten, stellen Sie es nur als intern bereit. Machen Sie const nicht öffentlich (auch wenn Sie der Meinung sind, dass Ihre Assemblys nicht außerhalb Ihrer Organisation verwendet werden). Eigenschaften bieten Ihnen programmatische Flexibilität für zukünftige Erweiterungen, ohne dass Sie Ihre Schnittstelle neu definieren müssen.
cfeduke
4

Eine leere statische Klasse ist angemessen. Verwenden Sie mehrere Klassen, damit Sie gute Gruppen verwandter Konstanten erhalten und nicht eine riesige Globals.cs-Datei.

Berücksichtigen Sie für einige int-Konstanten außerdem die Notation:

[Flags]
enum Foo
{
}

Dies ermöglicht es , die Werte wie Flags zu behandeln .

leeres Set
quelle
"Verwenden Sie mehrere Klassen, damit Sie gute Gruppen verwandter Konstanten erhalten und nicht eine riesige Globals.cs-Datei." Ich glaube, dies ist die beste Empfehlung. Gibt es nicht einige Designmuster? Ich kenne keinen mit Namen, oder?
Greg
3

Eine weitere Abstimmung für die Verwendung von web.config oder app.config. Die Konfigurationsdateien sind ein guter Ort für Konstanten wie Verbindungszeichenfolgen usw. Ich möchte lieber nicht auf die Quelle schauen müssen, um diese Art von Dingen anzuzeigen oder zu ändern. Eine statische Klasse, die diese Konstanten aus einer .config-Datei liest, kann ein guter Kompromiss sein, da Ihre Anwendung auf diese Ressourcen zugreifen kann, als wären sie im Code definiert, aber dennoch die Flexibilität bietet, sie in einer leicht sichtbaren / bearbeitbaren Datei zu haben Platz.

3Dave
quelle
2
Eine Verbindungszeichenfolge ist keine Konstante, sondern eine Einstellung. Es könnte sein, dass das OP wirklich auch Einstellungen statt Konstanten bedeutet, aber ich sehe keine Beweise dafür.
Jon Skeet
Ich bin anderer Ansicht. String-Literale sind per Definition Konstanten. Das Ändern der Zeichenfolge in einer Konfigurationsdatei entspricht in etwa dem Ändern des Codes und dem erneuten Kompilieren. würde das es nicht zu einer Konstante machen? Das glaube ich nicht.
3Dave
2
@ David - Nicht wahr. Einem Compiler ist es egal, welchen Wert Sie in Ihrer Konfigurationsdatei haben - dieser wird zur Laufzeit gelesen.
Philip Wallace
@PhilipW Ich verstehe das. Mein Punkt war, dass (als Antwort auf Jon Skeets Kommentar) eine bestimmte Verbindungszeichenfolge eine Konstante ist, wie alle Zeichenfolgenliterale. Die Tatsache, dass eine "Konstante" geändert werden kann - sei es durch Ändern der Konfigurationsdatei und Abrufen des neuen Werts durch Ihre App aus dieser Konfigurationsdatei oder durch Ändern des Literal-Codes, der eine Neukompilierung / Bereitstellung erfordern würde - nicht Machen Sie es zu einer "Einstellung". Die Zeichenfolge selbst ist unabhängig von ihrem Container konstant. Ich verstehe und stimme Ihrem Standpunkt zu - es war einfach nicht das, was ich gesagt habe.
3Dave
1
Nach meiner Erfahrung muss sich Ihr "konstanter" Wert irgendwann in unvorhergesehener Zukunft ändern, selbst wenn Sie dachten, dass dies in einer Million Jahren niemals der Fall sein würde. Ich denke, dass dies in einer .config-Datei viel einfacher ist als das Ändern des Quellcodes. Am Ende ist alles eine Kulisse.
NinjaBomb
1

Ja, ein static classzum Speichern von Konstanten wäre in Ordnung, mit Ausnahme von Konstanten, die sich auf bestimmte Typen beziehen.

bruno conde
quelle
Genau das versuche ich zu tun. Ich möchte, dass sie als Mitglieder der Klasse erscheinen, für die sie sind. aber ich möchte sie nicht zu den Klassen hinzufügen, da die Konstanten abhängig von der Firma variieren, für die ich die Arbeit mache. Ich habe noch nichts über Erweiterungskonstanten oder Eigenschaften gefunden. aber ich könnte diese Idee aufgeben, weil ich nicht möchte, dass sie als Mitglieder erscheinen, wenn ich diese Klassen serialisiere
Symbiont
0

Wenn diese Konstanten Dienstreferenzen oder Schalter sind, die das Anwendungsverhalten beeinflussen, würde ich sie als Anwendungsbenutzereinstellungen einrichten. Auf diese Weise müssen Sie sie nicht neu kompilieren, wenn sie geändert werden müssen, und Sie können sie dennoch über die statische Eigenschaftenklasse referenzieren.

Properties.Settings.Default.ServiceRef
Aaron
quelle
0

Ich würde statische Klasse mit statischer schreibgeschützter Klasse vorschlagen. Das folgende Code-Snippet finden Sie unten:

  public static class CachedKeysManager
    {
        public static readonly string DistributorList = "distributorList";
    }
KAPIL SHARMA
quelle