在C#中实现全局常量的最佳方法是什么?

时间:2022-09-02 11:38:08

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

我有一个Common项目,我在其中添加了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!

我知道有3种解决方案,但它们都有一个重要问题。调用程序集将包含my常量的副本,这意味着如果我必须更改常量值,我将必须编译我的Common程序集和调用程序集程序!

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)?

除了将它们存储在web.config文件(没有intellisense)之外,在C#中定义公共常量的最佳方法是什么?

7 个解决方案

#1


6  

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.

这取决于。如果它确实是一个不会改变的常量,即使在未来版本的代码中,那么const也没问题。否则请使用静态只读字段。

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.

const将嵌入到调用程序集中,而对于静态只读,调用程序集只包含对该字段的引用。这意味着const需要在更改值时重新编译所有相关代码,而public readonly使用新值,即使不重新编译调用程序集也是如此。

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:

如果要将“常量”存储在配置文件中,但是像Intellisense一样,则可以使用不带公共设置器的属性。然后在运行时从配置文件中填充它。但我认为配置值首先不应该是静态的。对于配置值,我使用某种单独的单元,最好是IoC变体,而不是Class.Instance变体。所以我只需要定义如下界面:

interface IMyConfig
{
  string Key{get;}
}

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

并且需要此配置的类将其作为构造函数参数:

public MyClass(IMyConfig config)
{
    ...
}

#2


5  

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.

如果你认为你要改变它并且你担心必须编译它,那么为什么不在web配置文件中使用appSettings?这就是它的用途。如果你真的需要智能感知,那么你可以将一个类放在一个读取配置值的程序集中,并将其作为属性公开,以便于引用。如果它是敏感数据,那么我不会把它放在配置文件中,我只是编译它,因为你不想破坏你的应用程序。

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

它可能不是您的解决方案的答案,但它可能会给您一些其他的想法。

#3


2  

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

如果你正在激活fxCop(Visual Studio发行版中包含的代码分析工具),你可能会因为改变常量而成为:

public static readonly string ConstName = "a value";

public static readonly string ConstName =“a value”;

#4


2  

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.

我不确定我是否完全理解这个问题...你是否要求一个解决方案来存储一些全局变量,这些变量不会导致重新编译到引用那些全局变量的程序集,如果你改变它们?如果是这样,那么为什么不考虑根据控制反转原理重新设计您的架构?想“不要打电话给我们,我们会打电话给你”好莱坞原则。如果需要某些const的所有程序集只调用一个接口(它们拥有),它接受一个具有所需值的属性,然后你有一个实现这些接口的常量项目(通过引用那些项目然后实现这些接口)那么当你改变常量的值时,那些项目永远不需要重新编译。

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.

我确定你知道它们但是读了SOLID原则,“D”是依赖性倒置原则(控制反转)。我认为考虑到你的担忧(假设我已经理解你了),他们可以真正帮助你。

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

控制反转的一个例子可以简单如下:

MyService.dll :

MyService.dll:

public class MyService
{

    // injected dependency
    public IMyConstants MyConstants { get; set; }

    public MyMethod(){

        // get your query...
        var query = IMyConstants.Query;
    }

}

MyConstants.dll :

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.

所以myconstants.dll引用myservice.dll而不是相反(意味着myservices不需要重新编译)。然后,引导代码(将其全部设置并注入依赖关系)存在于其他地方。

Sorry if I misunderstood you, hope that helps though!

对不起,如果我误解了你,希望尽管有帮助!

#5


0  

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.

在大多数情况下,我更喜欢第二个选项,因为它不会导致问题(通过复制值到其他程序集)。速度可能比常数慢,但这种纳秒速度还不成熟。

#6


0  

You could use the Cache object and define them in Global.asax

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

#7


0  

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

如前所述,情况并非如此:

  • const: is contant and cannot be modified except by recompiling.
  • const:是有效的,除非重新编译,否则无法修改。
  • readonly: the value is initialized in the declaration or in the constructor and stay readonly after.
  • readonly:该值在声明或构造函数中初始化,并在之后保持只读。

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

当字段声明包含只读修饰符时,声明引入的字段的赋值只能作为声明的一部分或在同一个类的构造函数中出现

#1


6  

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.

这取决于。如果它确实是一个不会改变的常量,即使在未来版本的代码中,那么const也没问题。否则请使用静态只读字段。

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.

const将嵌入到调用程序集中,而对于静态只读,调用程序集只包含对该字段的引用。这意味着const需要在更改值时重新编译所有相关代码,而public readonly使用新值,即使不重新编译调用程序集也是如此。

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:

如果要将“常量”存储在配置文件中,但是像Intellisense一样,则可以使用不带公共设置器的属性。然后在运行时从配置文件中填充它。但我认为配置值首先不应该是静态的。对于配置值,我使用某种单独的单元,最好是IoC变体,而不是Class.Instance变体。所以我只需要定义如下界面:

interface IMyConfig
{
  string Key{get;}
}

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

并且需要此配置的类将其作为构造函数参数:

public MyClass(IMyConfig config)
{
    ...
}

#2


5  

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.

如果你认为你要改变它并且你担心必须编译它,那么为什么不在web配置文件中使用appSettings?这就是它的用途。如果你真的需要智能感知,那么你可以将一个类放在一个读取配置值的程序集中,并将其作为属性公开,以便于引用。如果它是敏感数据,那么我不会把它放在配置文件中,我只是编译它,因为你不想破坏你的应用程序。

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

它可能不是您的解决方案的答案,但它可能会给您一些其他的想法。

#3


2  

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

如果你正在激活fxCop(Visual Studio发行版中包含的代码分析工具),你可能会因为改变常量而成为:

public static readonly string ConstName = "a value";

public static readonly string ConstName =“a value”;

#4


2  

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.

我不确定我是否完全理解这个问题...你是否要求一个解决方案来存储一些全局变量,这些变量不会导致重新编译到引用那些全局变量的程序集,如果你改变它们?如果是这样,那么为什么不考虑根据控制反转原理重新设计您的架构?想“不要打电话给我们,我们会打电话给你”好莱坞原则。如果需要某些const的所有程序集只调用一个接口(它们拥有),它接受一个具有所需值的属性,然后你有一个实现这些接口的常量项目(通过引用那些项目然后实现这些接口)那么当你改变常量的值时,那些项目永远不需要重新编译。

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.

我确定你知道它们但是读了SOLID原则,“D”是依赖性倒置原则(控制反转)。我认为考虑到你的担忧(假设我已经理解你了),他们可以真正帮助你。

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

控制反转的一个例子可以简单如下:

MyService.dll :

MyService.dll:

public class MyService
{

    // injected dependency
    public IMyConstants MyConstants { get; set; }

    public MyMethod(){

        // get your query...
        var query = IMyConstants.Query;
    }

}

MyConstants.dll :

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.

所以myconstants.dll引用myservice.dll而不是相反(意味着myservices不需要重新编译)。然后,引导代码(将其全部设置并注入依赖关系)存在于其他地方。

Sorry if I misunderstood you, hope that helps though!

对不起,如果我误解了你,希望尽管有帮助!

#5


0  

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.

在大多数情况下,我更喜欢第二个选项,因为它不会导致问题(通过复制值到其他程序集)。速度可能比常数慢,但这种纳秒速度还不成熟。

#6


0  

You could use the Cache object and define them in Global.asax

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

#7


0  

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

如前所述,情况并非如此:

  • const: is contant and cannot be modified except by recompiling.
  • const:是有效的,除非重新编译,否则无法修改。
  • readonly: the value is initialized in the declaration or in the constructor and stay readonly after.
  • readonly:该值在声明或构造函数中初始化,并在之后保持只读。

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

当字段声明包含只读修饰符时,声明引入的字段的赋值只能作为声明的一部分或在同一个类的构造函数中出现