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

发布于 2024-12-20 04:59:35 字数 436 浏览 1 评论 0原文

我有一个 Common 项目,在其中添加了 QueryStringNames 的公共常量。

我知道通常常量应该是内部常量或私有常量,但我在这里需要公共常量,因为我想允许全局访问查询字符串名称、会话密钥等。

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

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

除了将它们存储在 web.config 文件(没有智能感知)中之外,在 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)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

む无字情书 2024-12-27 04:59:35

这取决于。如果它确实是一个不会改变的常量,即使在代码的未来版本中,那么 const 就可以了。否则使用static readonly字段。

const 将嵌入到调用程序集中,而使用 static readonly 时,调用程序集仅包含对该字段的引用。这意味着每当您更改值时,const 都需要重新编译所有依赖代码,而 public readonly 即使不重新编译调用程序集也会使用新值。

如果您想将“常量”存储在配置文件中,但像​​ Intellisense 一样,您可以使用没有公共设置器的属性。然后在运行时从配置文件中填充它。但我认为配置值首先就不应该是静态的。对于配置值,我会使用某种类型的单例,最好是 IoC 变体,而不是 Class.Instance 变体。所以我只需定义一个如下所示的接口:

interface IMyConfig
{
  string Key{get;}
}

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

public MyClass(IMyConfig config)
{
    ...
}

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)
{
    ...
}
山人契 2024-12-27 04:59:35

如果您认为要更改它并且担心必须编译它,那么为什么不在 Web 配置文件中使用 appSettings 呢?这就是它的用途。如果您确实需要智能感知,那么您可以在其中一个程序集中放置一个类,该程序集读取配置值并将其公开为属性以便于引用。如果它是敏感数据,那么我不会将其放入配置文件中,无论如何我都会编译它,因为您不想损害您的应用程序。

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

这是引用该值的类,它为您提供智能感知,将来能够轻松更改它,并且无需重新编译任何内容。

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

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

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

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.

泡沫很甜 2024-12-27 04:59:35

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

我相信您无论如何都知道它们,但请阅读 SOLID原则,“D”是依赖倒置原则(控制反转)。我认为考虑到您的担忧(假设我正确理解了您),他们确实可以帮助您。

控制反转的示例可以简单如下:

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

}

因此 myconstants.dll 引用 myservice.dll,而不是相反(意味着 myservices 不需要重新编译)。然后引导代码(用于设置所有内容并注入依赖项)位于其他地方。

抱歉,如果我误解了您的意思,希望对您有所帮助!

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!

坏尐絯 2024-12-27 04:59:35

如果您正在激活 fxCop(Visual Studio 发行版中包含的代码分析工具),您可能会收到将常量更改为的建议:

public static readonly string ConstName = "a value";

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";

醉生梦死 2024-12-27 04:59:35

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

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.

一城柳絮吹成雪 2024-12-27 04:59:35

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

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

南…巷孤猫 2024-12-27 04:59:35

如前所述,这不是同一个场景:

  • const: 是连续的,除非重新编译,否则无法修改。
  • readonly:该值在声明或构造函数中初始化,之后保持只读状态。

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文