代码之家  ›  专栏  ›  技术社区  ›  devuxer

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

  •  7
  • devuxer  · 技术社区  · 14 年前

    在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。我仍然好奇,如果只有一个getter返回一个值而没有其他值,那么它是否有任何缺点。

    6 回复  |  直到 9 年前
        1
  •  10
  •   John Saunders    14 年前

    实际上,选项1和2是等效的。

    在我看来,实际上有三种不同的情况:

    • 你肯定地知道,弦永远不会改变。这样做是合理的 const . (例如, Math.PI 是常数。这不会很快改变。)在过度使用时,会有一些微妙的记忆暗示。 static readonly 但它们不太可能影响你。如果值可能更改,则不应执行此操作 由于其他地方给出的原因,您不希望在这种情况下重新编译所有调用方。请注意,对于许多项目(特别是内部公司项目),重新编译所有调用方确实不是问题。

    • 您认为这个字符串将来可能会改变,但您知道它在任何一个版本中都是一个常量。在这种情况下,A public static readonly 场没问题。请记住,使用字符串这样做是可以的,因为它们是不可变的,但是您不应该使用任何可变类型,如数组。(公开不可变集合或使用属性并每次返回一个新副本。)

    • 你认为字符串可能会改变,甚至可能在程序的生命周期内改变…例如,“当前日期,格式”。在这种情况下,使用公共静态只读 财产 (只有一个吸气剂)。请注意,从只读字段更改为只读属性是 来源 -兼容的更改,但不是 二元的 -兼容的变化-所以如果你已经选择了我的第二个子弹,但需要改变到第三个,你需要重新编译所有的东西。

        2
  •  5
  •   Michael Mrozek    14 年前

    考虑

    public static readonly string myVar = "something";
    

    原因:当你暴露(然后在别处消费)时 const , the 康斯特 嵌入在消费类型的元数据中。

    public static readonly 不是的,因为 static readonly 它只花费你一次实例化,而且它是不可变的,就像一个 康斯特 .

        3
  •  2
  •   Hans Passant    14 年前

    正确的选择是4:

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

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

    只读字段不能出现这种情况,其他程序集将始终读取更新的值。如果你使用const,一定要保证它们是私有的。

        4
  •  2
  •   Chris Frederick    13 年前

    const 成员是类成员,而不是实例成员(换句话说, 康斯特 暗示 static )

        5
  •  1
  •   John S.    14 年前

    如果我能投赞成票——我会投赞成票。此外,您的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初始化。因此,在这种情况下,对象的初始化是不必要的,您总是希望尽可能使用static,因为这样可以避免这样做。

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

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

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

    现在,向房间里的白象讲话。readonly和const的区别在于cont发生在编译时,readonly发生在运行时。静态只读初始化一次,而非静态只读为每个实例初始化一次。例如,如果您要求您的问题执行一些操作,例如为永远不会更改的错误消息创建一个常量字符串类,则使用选项3,而不是只读静态或其他。考虑到在运行时尝试初始化数百条错误消息,而不是在编译时,您将看到明显的性能差异。此外,由于您清楚地声明它是一个“永远不会更改的字符串”,因此在这种情况下甚至不应考虑只读,因为“…它永远不会更改”。const和readonly有它们的位置,但readonly不适用于永远不会更改并且在编译时已知的项。

        6
  •  1
  •   user370770    9 年前

    物业似乎是更好的选择,因为 string 然后不会嵌入到元数据中。 const 实际上是供内部使用的(例如,版本号可以 康斯特 或者对于绝对不会改变的值,就引用它的代码而言。