【问题标题】:Declaring a long constant byte array声明一个长的常量字节数组
【发布时间】:2013-03-11 16:47:24
【问题描述】:

我有一个长字节数组,需要在我的 C# 代码中声明。我做这样的事情:

public static class Definitions
{
    public const byte[] gLongByteArray = new byte[] { 
        1, 2, 3,
        //and so on
    };
}

但我得到一个错误,即 const 数组只能用空值初始化。

如果我将const 更改为static,它会编译,但我的问题是——当我将它声明为public static byte[] gLongByteArray 时,它不会在每次加载我的应用程序时都被初始化,对吧?在这种情况下,gLongByteArray 变量将简单地指向一个在加载到内存中的已编译 exe/dll 文件中定义的数组。我问的原因是因为这个数组很长,我不希望我的程序在每次应用启动时都浪费 CPU 周期来加载它,或者更糟糕的是,引用了这个类......

【问题讨论】:

  • 对性能的影响很小,即使您可以这样做。更大的问题是byte[] 不是一个很好的常量候选者。建议对不应该改变的事物使用常量,但是字节序列(尤其是长字节序列)在未来的实现中可能会发生变化。使用“const”会导致编译器“烘焙”对常量的所有引用,这意味着常量值在整个代码中重复。如果您稍后更改常量,则只有针对新常量编译的那些模块才会具有新值。
  • 正如其他人所说,不要根据猜测做出性能决定;根据事实制作它们。创建一个实际大小的数组并测量您的启动性能,无论是否使用它。然后你就会知道它是否有效果。由常量初始化的大字节数组得到相当有效的处理。
  • @ahmd0:我听说过调试器;调试器用于查找和删除错误,因此得名。您需要的工具是profiler,而不是debugger。 Profiler 确定时序数据并将其分配给代码。事实上,您应该永远在运行调试器时尝试获取性能数据。运行时知道附加了一个调试器,并故意降低您的程序运行效率,以便可以更轻松地对其进行调试。请记住,您的客户不会在调试器中运行程序,因此如果您想了解他们的经验,也不应该这样做。
  • 但更笼统地说:我无法查看生成的代码并告诉您它的运行速度。如果这是你拥有的超能力,那很好,但大多数人没有这种超能力。我没有开发那种超能力,而是使用分析器。
  • @ahmd0:根据我的经验,人们经常在别人身上看到他们自己所做的事情。你提出了一个讽刺的反问,比如“听说过调试器吗?”然后假设我的回答同样讽刺。它不是。我给你很好的建议,免费的。很遗憾听到它不受欢迎。

标签: c# arrays constants


【解决方案1】:

您不能创建 const 数组。根据documentation

用户定义的类型,包括类、结构体和数组,不能是const

您必须像这样将其声明为静态只读字段

public static class Definitions
{
    public static readonly byte[] gLongByteArray = new byte[] { 
        1, 2, 3,
        //and so on
    };
}

当然,没有什么可以阻止某人在运行时覆盖您的数组元素,如下所示:

Definitions.gLongByteArray[0] = 0xFF; 

您必须使用 @Virtlink 建议的内置集合之一或创建您自己的自定义只读数组类来防止这种情况发生 (example)。

【讨论】:

    【解决方案2】:

    编译时常量(那些用const 关键字声明的)受到严格限制。不必执行任何代码来获得这样的常量,否则它不可能是编译时常量。 const 常量默认为 static

    如果你想创建一个常量并且你不能使用编译时常量,你可以使用static readonly来代替:

    public static readonly byte[] longByteArray = new byte[] { 1, 2, 3, 4, 5 };
    

    static 关键字确保它只被初始化一次,并且是声明类型的一部分(而不是每个实例)。 readonly 关键字确保 longByteArray 变量 之后不能更改。

    Definitions.longByteArray = new byte[] { 4, 5, 6 };   // Not possible.
    

    警告:数组是可变的,所以在上面的代码中我可以仍然这样做:

    Definitions.longByteArray[3] = 82;                    // Allowed.
    

    为防止这种情况发生,请将类型设置为不是数组而是只读集合接口,例如 IEnumerable<T>IReadOnlyList<T>,或者更好的是只读集合类型,例如 ReadOnlyCollection<T>允许通过强制转换进行修改。

    public static readonly IReadOnlyList<byte> longByteArray = new byte[] { 1, 2, 3, 4, 5 };
    

    【讨论】:

    • 很好的答案,但是您的示例不会编译,因为byte a = 82974; 是编译时错误。
    • @AlexeiLevenkov 不错。我只需要想出一些随机数字。 :P
    • 在最后一个使用 IReadOnlyLIst 的示例中,我仍然可以将其转换为 byte[] 并修改数组中的值。如您所见here。如果那是一个列表,您可以在最后使用 AsReadonly()。
    • @jcmcbeth 如果疼,不要这样做。如果您明确地围绕界面进行转换,那么您实际上是在声明您知道自己在做什么并接受后果。我可以在未来的版本中更改底层实现,你的演员将失败。
    • @Virtlink 有了这个逻辑,还不如根本不让它只读,如果你正在修改它,你知道你在做什么并接受后果。
    【解决方案3】:

    静态类将在您首次加载应用程序时进行初始化。不要担心性能,除非您专门测量过这是一个问题。

    【讨论】:

    • 从技术上讲,静态初始化发生在可变时间,具体取决于引用类的方式/时间。这很少是一个问题,但值得了解。保证至少在您引用该字段时已运行。
    【解决方案4】:

    将所有内容写入文件并作为资源嵌入!

    【讨论】:

      猜你喜欢
      • 2012-10-19
      • 1970-01-01
      • 2011-04-01
      • 2014-02-07
      相关资源
      最近更新 更多