如何最好地在 C# 中实现可公开访问的常量

发布于 2024-09-02 17:51:11 字数 823 浏览 4 评论 0原文

在 C# 中实现可公开访问的常量似乎有三种选择。我很好奇是否有任何充分的理由选择其中之一,或者这只是个人喜好问题。

选择 1 - 私有字段加属性 getter

private const string _someConstant = "string that will never change";

public string SomeConstant
{
    get { return _someConstant; }
}

选择 2 - 仅属性 getter

public string SomeConstant
{
    get { return "string that will never change"; }
}

选择 3 - 仅公共字段

public const string SomeConstant = "string that will never change";

您推荐哪个?为什么?


更新

显然,这已经变成了使用const还是static readonly的讨论。这不完全是我的意图,但它确实告诉我选择 3 绝对是一个坏主意,因为如果 const 的值在未来版本中发生变化,则需要重新编译所有引用程序集。

然而,我认为还没有人真正讨论过选择 2。我仍然很好奇如果只返回一个值而没有其他任何吸气剂是否有任何缺点。

There seem to be three choices for implementing publicly accessible constants in C#. I'm curious if there are any good reasons to choose one over the other or if it's just a matter of personal preference.

Choice 1 - private field plus property getter

private const string _someConstant = "string that will never change";

public string SomeConstant
{
    get { return _someConstant; }
}

Choice 2 - property getter only

public string SomeConstant
{
    get { return "string that will never change"; }
}

Choice 3 - public field only

public const string SomeConstant = "string that will never change";

Which do you recommend and why?


Update

Apparently, this has turned into a discussion of whether to use const or static readonly. Not exactly what I intended, but it did teach me that Choice 3 is definitely a bad idea because, if the value of the const changes in a future version, it requires all referencing assemblies to be recompiled.

However, I don't think anyone has really discussed Choice 2 yet. I'm still curious if there's any disadvantage with having just a getter that returns a value and nothing else.

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

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

发布评论

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

评论(6

梦一生花开无言 2024-09-09 17:51:11

选择 1 和 2 确实是等效的。

在我看来,确实存在三种不同的情况:

  • 您确信该字符串永远不会改变。在这种情况下,将其设置为 const 是合理的。 (例如,Math.PI 是 const。这不会很快改变。)使用 static readonly 执行此操作会产生一些微妙的内存影响,但它们不太可能影响你。如果值可能会发生变化,并且由于其他地方给出的原因,您不想在这种情况下重新编译所有调用者,则不应执行此操作。请注意,对于许多项目(特别是公司内部的项目)来说,重新编译所有调用者实际上并不是问题。

  • 您认为该字符串将来可能会发生变化,但您知道它在任何一个版本中都将始终是一个常量。在这种情况下,public static readonly 字段就可以了。请记住,可以对字符串执行此操作,因为它们是不可变的,但不应该对任何可变类型(例如数组)执行此操作。 (公开不可变集合或使用属性并每次返回一个新副本。)

  • 您认为字符串可能会更改,甚至可能在程序的生命周期内更改...例如,“当前日期,格式化”。在这种情况下,请使用公共静态只读属性(仅具有 getter 的属性)。请注意,从只读字段更改为只读属性是源代码兼容的更改,而不是二进制兼容的更改 - 所以如果您已经同意我的第二个项目符号,但随后需要更改为第三个,您需要重新编译所有内容。

Choices 1 and 2 are equivalent, really.

It seems to me there are really three different situations:

  • You know for certain that the string will never, ever change. In this case it's reasonable to make it const. (For example, Math.PI is const. That's not going to change any time soon.) There are some subtle memory implications in doing this over using static readonly, but they're very unlikely to affect you. You shouldn't do this if the value may change and you don't want to recompile all callers in that situation, for the reasons given elsewhere. Note that for many projects (particularly internal corporate ones) it's really not a problem to recompile all callers.

  • You think the string might change in future, but you know it will always be a constant within any one version. In this case, a public static readonly field is okay. Bear in mind that it's fine to do this with strings as they're immutable, but you shouldn't do this with any mutable types such as arrays. (Either expose immutable collections or use a property and return a new copy each time.)

  • You think the string might change, and it could even change within the lifetime of a program... for example, "the current date, formatted". In this case, use a public static read-only property (one with only a getter). Note that changing from a readonly field to a read-only property is a source-compatible change, but not a binary-compatible change - so if you have plumped for my second bullet but then need to change to the third, you need to recompile everything.

暖伴 2024-09-09 17:51:11

考虑

public static readonly string myVar = "something";

原因:当您公开(然后在其他地方使用)const 时,const 会嵌入到使用类型的元数据中。

public static readonly 则不然,而且由于它是 static readonly,它只需要实例化一次,而且它像 const 一样是不可变的。 。

Consider

public static readonly string myVar = "something";

Reason: when you expose (and then consume elsewhere) a const, the const is embedded in the consuming type's metadata.

A public static readonly isn't, and since it's static readonly, it only costs you for instantiation once, and it is immutable like a const.

寄居人 2024-09-09 17:51:11

正确的选择是选择#4:

 public static readonly string SomeConstant = "string that might change in a new version";

使用只读字段而不是公共常量很重要。 const 的字面值被编译到 IL 中。如果您更改 const 值并重新编译使用它的一个程序集,那么您现在将与其他也使用该 const 的程序集不匹配。这些其他程序集仍将使用旧的 const 值运行。 非常很难诊断。

只读字段不会发生这种情况,其他程序集将始终读取更新的值。如果您使用 const,请确保始终将它们设为私有。

The proper one is choice #4:

 public static readonly string SomeConstant = "string that might change in a new version";

Using a readonly field instead of a public const is important. The literal value of a const is compiled into the IL. If you change the const value and recompile one assembly that uses it, you'll now have a mismatch with other assemblies that use the const as well. Those other assemblies will still run with the old const value. Very hard to diagnose.

This cannot happen with a readonly field, the other assemblies will always read the updated value. If you use const, be sure to always make them private.

魂ガ小子 2024-09-09 17:51:11

const 成员是类成员,而不是实例成员(换句话说,const 意味着static)。

const members are class members, not instance members (in other words, const implies static).

浅黛梨妆こ 2024-09-09 17:51:11

如果我可以投票 - 我会投票赞成乔恩·斯基特的答案。添加到它,您的 #1 和 #2 完全相同,如 IL:

.method public hidebysig specialname instance string 
    get_SomeConstant() cil managed
{
  // Code size       11 (0xb)
  .maxstack  1
  .locals init ([0] string CS$1$0000)
  IL_0000:  nop
  IL_0001:  ldstr      "string that will never change"
  IL_0006:  stloc.0
  IL_0007:  br.s       IL_0009
  IL_0009:  ldloc.0
  IL_000a:  ret
} // end of method Class1::get_SomeConstant

选项 #2:

.method public hidebysig specialname instance string 
    get_SomeConstant() cil managed
{
  // Code size       11 (0xb)
  .maxstack  1
  .locals init ([0] string CS$1$0000)
  IL_0000:  nop
  IL_0001:  ldstr      "string that will never change"
  IL_0006:  stloc.0
  IL_0007:  br.s       IL_0009
  IL_0009:  ldloc.0
  IL_000a:  ret
} // end of method Class2::get_SomeConstant

现在查看选项 #3 中所示。 3 号与 1 号和 2 号有很大不同。其原因是,如前所述,#3 是静态的,因为 const 是静态的。现在真正的问题是比较苹果与苹果,如果 #1 和 #2 是静态访问器怎么办?那么它们将与#3 更具可比性。目前,您必须为选项 1 和 2 初始化一个类,但不必为选项 3 初始化。因此,在这种情况下,对对象进行了不必要的初始化,并且您总是希望尽可能使用静态,因为为了避免这种情况。

现在让我们看看 IL 中的数字 3:

.field public static literal string SomeConstant = "string that will never change"

因此,为了提高效率,我将使用 #3。这也是我多年来许多有才华的同龄人教导我的。

现在,来解决房间里的白象问题。 Readonly 和 const 的区别在于 cont 发生在编译时,而 readonly 发生在运行时。静态只读初始化一次,而非静态只读每个实例初始化一次。例如,如果您要求您的问题执行诸如为永远不会更改的错误消息创建一类 const 字符串之类的操作,则使用选项#3,而不是只读静态或其他方式。考虑尝试在运行时而不是在编译时初始化数百条错误消息,您将看到明显的性能差异。另外,由于您明确指出它是一个“永远不会改变的字符串”,在这种情况下甚至不应该考虑只读,因为“......它永远不会改变”。 Const 和 ReadOnly 都有它们的位置,但 readonly 不适用于永远不会改变且在编译时已知的项目。

If I could vote up - I would vote up Jon Skeet's answer. To add on to it your #1 and #2 are exactly identical as shown here in IL:

.method public hidebysig specialname instance string 
    get_SomeConstant() cil managed
{
  // Code size       11 (0xb)
  .maxstack  1
  .locals init ([0] string CS$1$0000)
  IL_0000:  nop
  IL_0001:  ldstr      "string that will never change"
  IL_0006:  stloc.0
  IL_0007:  br.s       IL_0009
  IL_0009:  ldloc.0
  IL_000a:  ret
} // end of method Class1::get_SomeConstant

Option #2:

.method public hidebysig specialname instance string 
    get_SomeConstant() cil managed
{
  // Code size       11 (0xb)
  .maxstack  1
  .locals init ([0] string CS$1$0000)
  IL_0000:  nop
  IL_0001:  ldstr      "string that will never change"
  IL_0006:  stloc.0
  IL_0007:  br.s       IL_0009
  IL_0009:  ldloc.0
  IL_000a:  ret
} // end of method Class2::get_SomeConstant

Now looking at option #3. Number 3 is very different from #1 and #2. The reason for this is, as previously stated, #3 is static since const is static. Now the real question would be to compare apples to apples in that what if #1 and #2 where static accessors? Then they would be more comparable to #3. Currently you would have to initialize a class for option 1 and 2, but not for #3. Thus there is an unnecessary initialization of an object in this case and you always want to use static whenever possible because of to avoid just that.

Now lets look at number 3 in the IL:

.field public static literal string SomeConstant = "string that will never change"

So, for efficiency, I would use #3. This is also what I have been taught by many talented peers over the years.

Now, to address the white elephant in the room. Readonly and const differ in that cont occur at compile time and readonly occurs at run time. Static readonly is initialized once, while nonstatic readonly is initialized once per instance. If, for example you are asking your question to do something like create a class of const strings for error messages that will never change then use option #3 and not readonly static or otherwise. Think of trying to initialize hundreds of error messages at run time instead of at compile time, you will see a noticeable performance difference. Also, since you state clearly that it is a "string that will never change" readonly should not even be considered in this case because "...it will never change". Const and ReadOnly have their places, but readonly is not for items that will never change and are known at compile time.

关于从前 2024-09-09 17:51:11

属性似乎确实是更好的选择,因为返回的字符串不会嵌入到元数据中。 const 实际上是供内部使用的(例如,版本号可以制成 const,并且可以更改)或绝对不会更改的值作为引用它的代码。

A property really seems like the better choice because the returned string then isn't embedded in the metadata. const are really meant for internal use (as an example, a version number may be made into a const, and could change) or for values that absolutely will never change as far as the code that references it is concerned.

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