11
votes

Quelle est la meilleure façon de mettre en œuvre une constante globale en C #?

J'ai un projet commun à l'intérieur desquels j'ai ajouté mes constantes publiques pour QueryStringNames.

Je sais que les constantes devraient être aussi internes ou privées, mais j'avais besoin de constantes publiques ici comme je voudrais permettre à une mondiale Accès aux noms de la chaîne de requête, aux clés de session, etc.

Il y a 3 solutions que je connais, mais toutes ont une question importante. L'assemblage de l'appelant contiendrait la copie de ma constante qui signifie que si je dois modifier une valeur constante, je devrai compiler à la fois mon assemblage commun et l'assemblage de l'appelant! xxx

Quelle serait la meilleure approche pour définir les constantes publiques en C # à part les stocker dans le fichier web.config (qui n'a pas d'intellisense)?


6 commentaires

Vous pouvez avoir IntelliSense dans config si vous créez un schéma XSD approprié


Je suis un peu confus. Qu'est-ce que l'emplacement de stockage de la valeur (c.-à-d. Webconfig) a à voir avec l'accessabilité d'une copie de cette valeur en mémoire?


Vous avez raison @Sawyer; Cela ne résoudrait pas le problème si la const-même est à nouveau utilisé.


@Sawyer - Je pense que le point de l'OP était qu'il n'aurait pas à recompiler toutes les assemblées si c'était dans une configuration?


Vous ne pouvez pas utiliser la constante sans l'instance de classe, si vous voulez dire cela. J'utilise une classe de CO statique pour cela, donc j'utilise CO.PI, il n'est donc que de 3 personnages plus longtemps que d'utiliser PI en code.


Microsoft a une réponse: docs.microsoft.com/en-us/dotnet/cshaarp/programming-Guide/...


7 Réponses :


2
votes

Si vous activez FXCOP (outil d'analyse de code inclus dans Visual Studio Distribution), vous risquez d'obtenir SUGGEION pour changer constante pour devenir:

Constname String Static Static String = "Une valeur";


4 commentaires

Je n'ai pas de compilateur à remettre, mais je suis surpris que le mot clé statique soit requis ou même légal, compte tenu de la nature d'une valeur const .


blogs.msdn.com/b/csharpfaq/archive/2004/03/12/...


@Spender faisez-vous référence à une version antérieure de cette réponse? Parce que statique lisonly a certainement un sens. static n'est implicite que lorsque vous utilisez const et non lorsque vous utilisez lisonly .


@Codeinchaos: Il est possible que j'ai mal interprété la réponse. Au moment de poster mon commentaire, je pensais qu'il contenait les deux const et statique dans la même déclaration.



0
votes

Je préfère la 2e option dans la plupart des cas car elle ne causera pas de problème (par la valeur de copie à d'autres assemblages). La vitesse peut avoir une valeur plus lente que les constantes, mais ce type de vitesse nano-deuxième est assez immature.


0 commentaires

7
votes

Cela dépend. S'il s'agit vraiment d'une constante qui ne changera pas, même dans les versions futures de votre code, alors const code> va bien. D'autre partez avec un champ statique réadonly code>.

A const code> sera intégré à l'assemblage d'appel, alors qu'avec avec statique réadonnement code> uniquement l'assemblage d'appel contient une référence au champ. Cela signifie const code> nécessite une recompilation de tout code dépendant lorsque vous modifiez la valeur, alors que public réadonnant code> utilise la nouvelle valeur même sans recompiler l'assemblage d'appel. P>

Si vous souhaitez stocker la "constante" dans un fichier de configuration, mais comme IntelliSense, vous pouvez utiliser une propriété sans setter public. Puis remplissez-le du fichier de configuration au moment de l'exécution. Mais je dirais que les valeurs de configuration ne doivent pas être statiques code> en premier lieu. Pour les valeurs de configuration, j'utiliserais un singleton de quelque sorte, de préférence la variation du CIO et non la variation class.Instance code>. Donc, je définirais simplement une interface comme les suivantes: p> xxx pré>

et avez des classes qui ont besoin de cette configuration le prennent comme paramètre de constructeur: P>

public MyClass(IMyConfig config)
{
    ...
}


7 commentaires

Pourquoi?! J'ai testé et statique réadonner aurait également besoin de la recomilation de l'appelant.


Je suis à peu près sûr que la modification d'un champ statique réadonnant ne nécessite pas de recompiler l'appelant. L'assemblage appelant ne contient que le nom de votre champ et non la valeur de celui-ci.


@Codeinchaos est correct. Si vous deviez utiliser une constante, cette valeur est insérée par le compilateur, tandis que le champ Readonly est inséré à l'exécution (en déclaration ou dans le constructeur, en fonction de la manière dont vous mettez en œuvre la valeur réadonnée). Même une statique réadonner serait faite au moment de l'exécution, chaque fois que les champs statiques de la classe sont initialisés.


Je suis d'accord, s'il y a une possibilité, ils peuvent changer (et provoquer des recompiles), alors ils ne sont pas vraiment des constantes. Je préfère le const car ils sont plus faciles à utiliser dans des déclarations de commutation / cas. Mais si vous parlez de clés de QueryString & Session, changez ceux-ci provoquera une reconduction et un redéploiement de toute façon.


@Codeinchaos, il fait apparemment; Testez-le vous-même et voyez! Ou peut-être que je n'ai pas testé correctement.


@WILLIAM Peut-être que vous êtes confus par VS reconstruction de tous les assemblages à charge par défaut. Mais si vous prenez la nouvelle assemblée contenant du "statique en lecture seule", remplacez simplement cette DLL unique avec une version différente, tous les assemblages édifiants doivent toujours fonctionner et utiliser les nouvelles valeurs.


@Codeinchaos, j'avais copié manuellement les assemblées; sinon vs aurait tout reconstitué.



0
votes

Vous pouvez utiliser l'objet de cache et les définir dans global.asax


0 commentaires

6
votes

Si vous pensez que vous le changeriez et que vous êtes inquiet de devoir le compiler, alors pourquoi ne pas utiliser d'appsettings dans le fichier de configuration Web? C'est ce que c'est pour. Si vous avez vraiment besoin d'intellisense, vous pouvez simplement mettre une classe dans l'une des assemblées qui lit la valeur de configuration et l'expose comme une propriété pour faciliter le référencement. Si c'est des données sensibles, je ne le mettrais pas dans un fichier de configuration, je ne voudrais tout de même pas le compiler car vous ne souhaitez pas compromettre votre application.

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

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


7 commentaires

Je réécrireais le constructeur pour prendre un namevaluecollection ou quelque chose de similaire au lieu de l'avoir extraire de la propriété statique AppSettings . Puis injectez-le via IOC.


Ouais, j'espérais qu'il y aurait une solution plus simple sans utiliser le web.config. J'écrirais habituellement ma propre configuration et mon iconfig et une classe Singleton comme mon CustomConfigmanager pour avoir toutes ces propriétés comme en lecture seule et pour interagir avec le fichier physique une seule fois. Si une modification est requise, l'application doit être redémarrée. Le web.config est-il le seul moyen d'éviter ce problème?


Je ne sais pas si c'est le seul moyen de l'éviter. Je veux dire que vous pourrait le persistez dans un enregistrement de base de données également. De cette façon, vous pouvez changer la valeur si nécessaire et ne pas avoir à recompiler. Honnêtement, ce n'est vraiment pas ce complexe d'une solution; C'est assez simple imo.


@Codeinchaos, qui est totalement acceptable aussi, mais ma mise en œuvre résume la lecture de la configuration complètement et empêche le code client qui utilise la classe pour avoir à récupérer un namevaluecollection pour le transmettre. Gardez-le de manière vague couplée. Si vous devez écrire des tests d'unité contre la classe de configuration (je ne sais pas pourquoi vous le feriez, il n'ya pas de logique à tester), vous pouvez fournir un deuxième constructeur qui prend une nomeurocollection. Je pense que ce serait fini cependant.


Votre classe est étroitement couplée au mécanisme de stockage de configuration. Mais le code client ne doit pas construire des instances de myappConfigSettings . Le seul code construit myAppConfigSettings doit être le conteneur de la COI. Je ne parle pas de tester la classe de configuration, mais de tester les classes qui dépendent de la classe de configuration. Et tester avec une configuration différente semble joli standard pour moi.


Donc, si vous aviez besoin de tester des cours qui utilisent la configuration, ne pouviez-vous pas écrire une interface pour la classe de configuration, puis vous les moquer? Je ne suis pas un gourou de test unitaire mais c'est comme ça que je le ferais.


@Jlafay Oui, si vous avez une interface et que le code client ne fait référence qu'à l'interface et que jamais la classe (surtout pas la construction), votre classe va bien.



0
votes

Comme dit auparavant, ce n'est pas le même scénario:

  • Const: est en tentant et ne peut pas être modifié sauf par recompilation.
  • Readonly: la valeur est initialisée dans la déclaration ou dans le constructeur et restera à la fois après.

    Lorsqu'une déclaration de champ inclut un modificateur lisonly, les affectations aux champs introduites par la déclaration ne peuvent se produire que dans le cadre de la déclaration ou dans un constructeur de la même classe


3 commentaires

Pour le problème, j'ai souligné, ils se comportèrent tous les deux de même. Recommandation des appelants serait nécessaire dans le cas d'une modification, à moins que les valeurs soient initialisées à partir d'un fichier physique distinct tel qu'un fichier de configuration.


Dans votre cas, j'irais avec Const dans une classe d'assistance statique.


Vous n'avez pas compris le problème.



2
votes

Je ne suis pas sûr que si je comprends le problème complètement ... Vous demandez une solution à stocker certaines variables globales qui ne causeront pas de recompiles aux assemblages qui font référence à ces variables globales si vous les changez? Si oui, pourquoi ne pas essayer de penser à la refonte de votre architecture selon les Inversion du contrôle Principe ? Pensez «Ne nous appelez pas, nous vous appellerons» le principe hollywoodien. Si tous les assemblages qui nécessitent que certains const appellent juste une interface (qu'ils possèdent) qui exposent une propriété avec la valeur dont ils ont besoin, puis vous avez un projet de constantes qui mettent en œuvre cette interface (en faisant référence à ces projets, puis en mettant en œuvre ces interfaces) Ensuite, ces projets n'auront jamais besoin de recompubilité lorsque vous modifiez la valeur des constantes.

Je suis sûr que vous les connaissez de toute façon mais que vous avez une lecture sur le Principes solides ," D "Etre le principe d'inversion de dépendance (inversion du contrôle). Je pense que céder vos préoccupations (en supposant que je vous ai bien compris), ils pourraient vraiment vous aider.

Un exemple d'inversion du contrôle pourrait être aussi simple que:

myservice.dll : xxx

myConcstants.dll: xxx

donc les myConstants.dll références le myservice.dll plutôt que l'autre sens autour (ce qui signifie que mservices n'aura pas besoin de recompiler). Ensuite, le code bootstrapping (pour la définir et injecter des dépendances) vit ailleurs.

Désolé si je vous ai mal compris, espère que cela aide!


4 commentaires

Vous avez raison, la configuration doit être injectée via IOC et ne pas lire des membres statiques. Quelques Nitpicks: J'utiliserais l'injection de constructeur, et je n'utiliserais pas le nom constante ici, puisque une valeur de configuration n'est pas vraiment une constante. Si c'était vraiment une constante, nous n'aurions pas besoin de di ici.


Wikipedia cite le I dans Solide comme "principe de ségrégation d'interface". Je pense que le principe que vous voulez est "pousser, ne pas tirer".


Oui, ça sonne à peu près tout - tu sais ce que je veux dire cependant. Je me mêle juste avec des interprétations de di je pense!


À toute autre personne qui lit déjà mon commentaire ci-dessus - j'ai édité un peu pour contenir la référence correcte aux principes solides. Cheers @codeinchaos!