声明一个常量数组
是否可以写出类似下面的内容?
public const string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
Is it possible to write something similar to the following?
public const string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(16)
是的,但是你需要声明它是
readonly
而不是const
:原因是
const
只能应用于值已知的字段在编译时。您显示的数组初始值设定项不是 C# 中的常量表达式,因此它会产生编译器错误。将其声明为只读可以解决该问题,因为该值直到运行时才初始化(尽管保证在第一次使用该数组之前已初始化)。
根据您最终想要实现的目标,您还可以考虑声明一个枚举:
Yes, but you need to declare it
readonly
instead ofconst
:The reason is that
const
can only be applied to a field whose value is known at compile-time. The array initializer you've shown is not a constant expression in C#, so it produces a compiler error.Declaring it
readonly
solves that problem because the value is not initialized until run-time (although it's guaranteed to have initialized before the first time that the array is used).Depending on what it is that you ultimately want to achieve, you might also consider declaring an enum:
您无法创建“const”数组,因为数组是对象并且只能是
在运行时创建,const 实体在编译时解析。
您可以做的是将数组声明为“只读”。这有
与 const 效果相同,只是该值可以在运行时设置。只能是
设置一次后它就是一个只读(即常量)值。
You can't create a 'const' array because arrays are objects and can only be
created at runtime and const entities are resolved at compile time.
What you can do instead is to declare your array as "readonly". This has the
same effect as const except the value can be set at runtime. It can only be
set once and it is thereafter a readonly (i.e. const) value.
这是唯一正确的答案。您目前无法执行此操作。
所有其他答案都建议使用静态只读变量,这些变量与常量相似,但不同。常量被硬编码到程序集中。静态只读变量可以设置一次,可能在对象初始化时设置。
这些有时可以互换,但并非总是如此。
编辑:我想我应该把这个放进去,因为提出问题的人似乎对数组有点模糊。当你声明一个数组时,它是一个指向包含该数组的内存段的指针。它很简单,只是一个地址,没有复杂的逻辑控制它是否可读或可写。它给你一个指针,你可以用它做任何你想做的事情。
这就是为什么创建不可变数组有点棘手的部分原因。您可以编写一个包装数组的类,并且只允许通过返回副本来读取它,但它实际上不再只是一个数组,而是一个包装数组的对象。
有些人建议使用静态或只读来模拟您在创建 const 数组时会看到的行为。这些有一些副作用,对于普通读者来说可能并不明显。另外,如果将数组标记为只读,则标记的是指向该数组的指针,而不是数组本身。您可以根据需要更改数组的内容:
要真正获得 const 数组,需要更新 C# 和 MSIL 底层代码以允许从数组读取,但不允许写入。本页上的其他建议是解决此问题的各种创造性方法。
This is the only correct answer. You cannot currently do this.
All the other answers are suggesting using static read-only variables which are similar to, but not the same as a constant. A constant is hard coded into the assembly. A static read-only variable is settable once, probably as an object is initialized.
These are sometimes interchangeable, but not always.
EDIT: I thought I'd throw this in, as it seems like the person who asked the question was a little fuzzy about arrays. When you declare an array, it is a pointer to a segment of memory that contains the array. It is very simple in that it is just an address, with no complex logic controlling if it is readable or writable. It gives you a pointer, and you can do whatever you want with it.
This is part of the reason why it is a little tricky to make an immutable array. You could write a class that wraps the array and only allows reading of it by returning a copy, but then it really isn't just an array anymore, it is an object that wraps an array.
Some people have suggested using static, or read-only, to simulate the behavior you would see if you could create a const array. These have some side effects that might not be obvious to the casual reader. Also, if you mark an array with read-only, you are marking the pointer to the array, not the array itself. You can change the contents of the array as much as you want:
To truly get a const array, there would need to be an update to C# and the MSIL underlying code to allow reading from an array, but no writing. The other proposals on this page are various creative ways to work around this problem.
您可以将数组声明为
readonly
,但请记住,您可以更改readonly
数组的元素。正如科迪建议的那样,考虑使用枚举或 IList。
You can declare array as
readonly
, but keep in mind that you can change element ofreadonly
array.Consider using enum, as Cody suggested, or IList.
从 C# 6 开始,您可以这样编写:
另请参阅: C# :新的和改进的 C# 6.0(特别是“表达式主体函数和属性”一章)
这将创建一个只读静态属性,但它仍然允许您更改返回的数组的内容,但是当您再次调用该属性时,您将再次获得原始的、未更改的数组。
为了澄清起见,此代码与(或实际上是其简写)相同:
请注意,这种方法有一个缺点:实际上在每个引用上都实例化了一个新数组,因此如果您使用的是一个非常大的数组,这可能不是最有效的解决方案。
但是,如果您重复使用相同的数组(例如将其放入私有属性中),它将再次打开更改数组内容的可能性。
如果您想要一个不可变的数组(或列表),您也可以使用:
但是,这仍然存在更改的风险,因为您仍然可以将其转换回 string[] 并更改内容,如下所示:
Since C# 6 you can write it like:
See also: C# : The New and Improved C# 6.0 (specifically the chapter "Expression Bodied Functions and Properties")
This will make a read-only static property, but it will still allow you to alter the content of the array returned, but when you call the property again, you will get the original, unaltered array again.
For clarification, this code is the same as (or actually a shorthand for):
Please note that there is a downside to this approach: A new array is actually instantiated on each and every reference, so if you are using a very large array, this might not be the most efficient solution.
But if you re-use the same array (by putting it in a private attribute for instance) it will again open up the possibility to change the contents of the array.
If you want to have an immutable array (or list) you could also use:
But, this still has a risk for changes, as you can still cast it back to a string[] and alter the contents, as such:
为了完整起见,现在我们还有
ImmutableArray
任由我们使用。这应该是真正不可变的:需要 System.Collections.Immutable NuGet 引用。
For the sake of completeness, now we also have
ImmutableArray
s at our disposal. This should be truly immutable:Requires
System.Collections.Immutable
NuGet reference.您可以采取不同的方法:定义一个常量字符串来表示您的数组,然后在需要时将字符串拆分为数组,例如,
此方法为您提供一个常量,该常量可以存储在配置中并在需要时转换为数组。
You could take a different approach: define a constant string to represent your array and then split the string into an array when you need it, e.g.
This approach gives you a constant which can be stored in configuration and converted to an array when needed.
.NET Framework v4.5+ 解决方案,改进了 tdbeckett 的答案:
注意:鉴于集合在概念上是恒定的,因此将其设为静态以在类级别声明它可能是有意义的。
上面:
< strong>使用数组初始化属性的隐式支持字段一次。
请注意
{ get; }
- 即,仅声明属性 getter - 使属性本身隐式只读(尝试将readonly
与{ get; 结合起来) }
实际上是一个语法错误)。或者,您可以省略
{ get; }
并添加readonly
以创建一个字段而不是属性,如问题中所示,但将公共数据成员公开为属性而不是字段是一个好习惯的养成。创建一个类似数组的结构(允许索引访问),并且真正且稳健地只读 (概念上恒定,一旦创建),两者都涉及:
(甚至间接修改也是不可能的 - 与
IReadOnlyList
解决方案不同,其中a(string[ ])
强制转换可用于获得对元素的写访问权,如 mjepsen 的有用答案所示一个>.同样的漏洞也适用于
IReadOnlyCollection
接口,尽管名称与类相似< code>ReadOnlyCollection,甚至不支持索引访问,这使得它从根本上不适合提供类似数组的访问。)A .NET Framework v4.5+ solution that improves on tdbeckett's answer:
Note: Given that the collection is conceptually constant, it may make sense to make it
static
to declare it at the class level.The above:
Initializes the property's implicit backing field once with the array.
Note that
{ get; }
- i.e., declaring only a property getter - is what makes the property itself implicitly read-only (trying to combinereadonly
with{ get; }
is actually a syntax error).Alternatively, you could just omit the
{ get; }
and addreadonly
to create a field instead of a property, as in the question, but exposing public data members as properties rather than fields is a good habit to form.Creates an array-like structure (allowing indexed access) that is truly and robustly read-only (conceptually constant, once created), both with respect to:
(Even indirect modification isn't possible - unlike with an
IReadOnlyList<T>
solution, where a(string[])
cast can be used to gain write access to the elements, as shown in mjepsen's helpful answer.The same vulnerability applies to the
IReadOnlyCollection<T>
interface, which, despite the similarity in name to classReadOnlyCollection
, does not even support indexed access, making it fundamentally unsuitable for providing array-like access.)如果在 IReadOnlyList 接口后面声明一个数组,您将获得一个具有在运行时声明的常量值的常量数组:
在 .NET 4.5 及更高版本中可用。
If you declare an array behind an IReadOnlyList interface you get a constant array with constant values that is declared at runtime:
Available in .NET 4.5 and higher.
我相信你只能将其设置为只读。
I believe you can only make it readonly.
根据我的需要,我定义了
static
数组,而不是不可能的const
并且它可以工作:public static string[] Titles = { "德语", "西班牙语", "正确", "错误" };
For my needs I define
static
array, instead of impossibleconst
and it works:public static string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
这是一种执行您想要的操作的方法:
它与执行只读数组非常相似。
This is a way to do what you want:
It is very similar to doing a readonly array.
数组可能是只能在以下位置进行评估的事物之一
运行时。常量必须在编译时求值。尝试使用“只读”
而不是“常量”。
Arrays are probably one of those things that can only be evaluated at
runtime. Constants must be evaluated at compile time. Try using "readonly"
instead of "const".
快速解决方法,以防对某人有帮助。我需要一个 string[] 来作为属性的参数(在某些理论中为测试用例传递内联数据)。
readonly
在这里没有帮助。但是,我最终做了:Quick workaround in case it's helpful for someone. I needed a
string[]
to be an argument for an Attribute (passing inline data for a test case in some theory).readonly
won't help here. But, I ended up doing:最佳替代方案:
Best alternative:
作为替代方案,要解决只读数组的元素可修改问题,您可以使用静态属性。 (单个元素仍然可以更改,但这些更改只会在数组的本地副本上进行。)
当然,这不会特别有效,因为每次都会创建一个新的字符串数组。
As an alternative, to get around the elements-can-be-modified issue with a readonly array, you can use a static property instead. (The individual elements can still be changed, but these changes will only be made on the local copy of the array.)
Of course, this will not be particularly efficient as a new string array is created each time.