简体   繁体   中英

What's the best way to implement a global constant in C#?

I have a Common project inside which I've added my public constants for QueryStringNames.

I know generally constants should be as internal or private but I'd need public constants here as I'd like to allow a global access to the query string names, session keys, etc.

There are 3 solutions that I know of but all of them have an important issue. The caller assembly would contain the copy of my constant which means if I have to change a constant value, I'll have to compile both my Common assembly and the caller assembly!

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

What would be the best approach to define public constants in C# apart from storing them in the web.config file (which doesn't have intellisense)?

It depends. If it is truly a constant that won't change, even in future versions of your code, then const is fine. Else go with a static readonly field.

A const will get embedded into the calling assembly, whereas with static readonly the calling assembly only contains a reference to the field. This means const requires recompilation of all dependent code whenever you change the value, whereas public readonly uses the new value even without recompiling the calling assembly.

If you want to store the "constant" in a config file, but like Intellisense, you can use a property with no public setter. And then fill it from the config file at runtime. But I'd argue that configuration values should not be static in the first place. For configuration values I'd use a singleton of some sort, preferably the IoC variation and not the Class.Instance variation. So I'd just define an interface like the following:

interface IMyConfig
{
  string Key{get;}
}

And have classes that need this config take it as a constructor parameter:

public MyClass(IMyConfig config)
{
    ...
}

If you think you'd be changing it and you're worried about having to compile it, then why not use appSettings in the web config file? That's what it's for. If you really need intellisense then you could just put a class in one of the assemblies that reads the config value and exposes it as a property for easier referencing. If it's sensitive data then I wouldn't put it in a config file, I would just compile it anyways since you don't want to compromise your application.

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

Here's the class to reference that value, which gives you intellisense, ability to change it easily in the future, and without having to recompile anything

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

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

It may not be the answer to your solution but it may give you some other ideas.

If you are activating fxCop (code analysis tool included in Visual studio distribution), you may get sugestion to change constant to become:

public static readonly string ConstName = "a value";

I'm not sure if I understand the problem completely... you're asking for a solution to storing some global variables that won't cause recompiles to assemblies that reference those global variables if you change them? If so then why not try thinking about redesigning your architecture as per the Inversion of Control principle? Think "don't call us, we'll call you" the hollywood principle. If all the assemblies that require some const just call an interface (that they own) that exposes a property with the value they require, and then you have a project of constants that implement those interface (by referencing those projects and then implementing those interfaces) then those projects will never need recompilling when you change the value of the constants.

I'm sure you know them anyway but have a read up on the SOLID principles , "D" being the Dependency Inversion principle (Inversion of Control). I think given your concerns (assuming I've understood you right) they could really help you out.

An example of Inversion of Control could be as simple as:

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 { ... }

}

So the myconstants.dll references the myservice.dll rather than the other way around (meaning myservices won't need recompiling). Then the bootstrapping code (to set it all up and inject dependencies) lives elsewhere.

Sorry if I misunderstood you, hope that helps though!

I prefer the 2nd option in most case since it won't cause problem (by copy value to other assemblies). The speed may have a slower than constants but this kind of nano-second speed is pretty immature.

您可以使用Cache对象并在Global.asax中定义它们

As said before, it's not the same scenario:

  • const: is contant and cannot be modified except by recompiling.
  • readonly: the value is initialized in the declaration or in the constructor and stay readonly after.

When a field declaration includes a readonly modifier, assignments to the fields introduced by the declaration can only occur as part of the declaration or in a constructor in the same class

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM