声明一个常量数组

发布于 2024-10-19 16:56:40 字数 125 浏览 5 评论 0原文

是否可以写出类似下面的内容?

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 技术交流群。

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

发布评论

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

评论(16

预谋 2024-10-26 16:56:40

是的,但是你需要声明它是readonly而不是const

public static readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };

原因是const只能应用于值已知的字段在编译时。您显示的数组初始值设定项不是 C# 中的常量表达式,因此它会产生编译器错误。

将其声明为只读可以解决该问题,因为该值直到运行时才初始化(尽管保证在第一次使用该数组之前已初始化)。

根据您最终想要实现的目标,您还可以考虑声明一个枚举:

public enum Titles { German, Spanish, Corrects, Wrongs };

Yes, but you need to declare it readonly instead of const:

public static readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };

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:

public enum Titles { German, Spanish, Corrects, Wrongs };
我很OK 2024-10-26 16:56:40

您无法创建“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.

執念 2024-10-26 16:56:40

这是唯一正确的答案。您目前无法执行此操作。

所有其他答案都建议使用静态只读变量,这些变量与常量相似,但不同。常量被硬编码到程序集中。静态只读变量可以设置一次,可能在对象初始化时设置。

这些有时可以互换,但并非总是如此。

编辑:我想我应该把这个放进去,因为提出问题的人似乎对数组有点模糊。当你声明一个数组时,它是一个指向包含该数组的内存段的指针。它很简单,只是一个地址,没有复杂的逻辑控制它是否可读或可写。它给你一个指针,你可以用它做任何你想做的事情。

这就是为什么创建不可变数组有点棘手的部分原因。您可以编写一个包装数组的类,并且只允许通过返回副本来读取它,但它实际上不再只是一个数组,而是一个包装数组的对象。

有些人建议使用静态或只读来模拟您在创建 const 数组时会看到的行为。这些有一些副作用,对于普通读者来说可能并不明显。另外,如果将数组标记为只读,则标记的是指向该数组的指针,而不是数组本身。您可以根据需要更改数组的内容:

public class Demo
{
    private readonly int[] _foo = new int[] {0,1,2,3};
    
    public void ChangeArray()
    {
        _foo[1] = 42; // works
        _foo = new int[] { 0, 1, 2, 3, 5 }; // won't even compile
    }
}

要真正获得 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:

public class Demo
{
    private readonly int[] _foo = new int[] {0,1,2,3};
    
    public void ChangeArray()
    {
        _foo[1] = 42; // works
        _foo = new int[] { 0, 1, 2, 3, 5 }; // won't even compile
    }
}

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.

风为裳 2024-10-26 16:56:40

您可以将数组声明为 readonly,但请记住,您可以更改 readonly 数组的元素。

public readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
...
Titles[0] = "bla";

正如科迪建议的那样,考虑使用枚举或 IList。

public readonly IList<string> ITitles = new List<string> {"German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();

You can declare array as readonly, but keep in mind that you can change element of readonly array.

public readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
...
Titles[0] = "bla";

Consider using enum, as Cody suggested, or IList.

public readonly IList<string> ITitles = new List<string> {"German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();
謌踐踏愛綪 2024-10-26 16:56:40

从 C# 6 开始,您可以这样编写:

public static string[] Titles => new string[] { "German", "Spanish", "Corrects", "Wrongs" };

另请参阅: C# :新的和改进的 C# 6.0(特别是“表达式主体函数和属性”一章)

这将创建一个只读静态属性,但它仍然允许您更改返回的数组的内容,但是当您再次调用该属性时,您将再次获得原始的、未更改的数组。

为了澄清起见,此代码与(或实际上是其简写)相同:

public static string[] Titles
{
    get { return new string[] { "German", "Spanish", "Corrects", "Wrongs" }; }
}

请注意,这种方法有一个缺点:实际上在每个引用上都实例化了一个新数组,因此如果您使用的是一个非常大的数组,这可能不是最有效的解决方案。
但是,如果您重复使用相同的数组(例如将其放入私有属性中),它将再次打开更改数组内容的可能性。

如果您想要一个不可变的数组(或列表),您也可以使用:

public static IReadOnlyList<string> Titles { get; } = new string[] { "German", "Spanish", "Corrects", "Wrongs" };

但是,这仍然存在更改的风险,因为您仍然可以将其转换回 string[] 并更改内容,如下所示:

((string[]) Titles)[1] = "French";

Since C# 6 you can write it like:

public static string[] Titles => new string[] { "German", "Spanish", "Corrects", "Wrongs" };

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):

public static string[] Titles
{
    get { return new string[] { "German", "Spanish", "Corrects", "Wrongs" }; }
}

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:

public static IReadOnlyList<string> Titles { get; } = new string[] { "German", "Spanish", "Corrects", "Wrongs" };

But, this still has a risk for changes, as you can still cast it back to a string[] and alter the contents, as such:

((string[]) Titles)[1] = "French";
温馨耳语 2024-10-26 16:56:40

为了完整起见,现在我们还有 ImmutableArray任由我们使用。这应该是真正不可变的:

public readonly static ImmutableArray<string> Titles =
    ImmutableArray.Create(new[] { "German", "Spanish", "Corrects", "Wrongs" });

需要 System.Collections.Immutable NuGet 引用。

For the sake of completeness, now we also have ImmutableArrays at our disposal. This should be truly immutable:

public readonly static ImmutableArray<string> Titles =
    ImmutableArray.Create(new[] { "German", "Spanish", "Corrects", "Wrongs" });

Requires System.Collections.Immutable NuGet reference.

要走就滚别墨迹 2024-10-26 16:56:40

您可以采取不同的方法:定义一个常量字符串来表示您的数组,然后在需要时将字符串拆分为数组,例如,

const string DefaultDistances = "5,10,15,20,25,30,40,50";
public static readonly string[] distances = DefaultDistances.Split(',');

此方法为您提供一个常量,该常量可以存储在配置中并在需要时转换为数组。

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.

const string DefaultDistances = "5,10,15,20,25,30,40,50";
public static readonly string[] distances = DefaultDistances.Split(',');

This approach gives you a constant which can be stored in configuration and converted to an array when needed.

岛徒 2024-10-26 16:56:40

.NET Framework v4.5+ 解决方案,改进了 tdbeckett 的答案

using System.Collections.ObjectModel;

// ...

public ReadOnlyCollection<string> Titles { get; } = new ReadOnlyCollection<string>(
  new string[] { "German", "Spanish", "Corrects", "Wrongs" }
);

注意:鉴于集合在概念上是恒定的,因此将其设为静态以在级别声明它可能是有意义的。

上面:

A .NET Framework v4.5+ solution that improves on tdbeckett's answer:

using System.Collections.ObjectModel;

// ...

public ReadOnlyCollection<string> Titles { get; } = new ReadOnlyCollection<string>(
  new string[] { "German", "Spanish", "Corrects", "Wrongs" }
);

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 combine readonly with { get; } is actually a syntax error).

    • Alternatively, you could just omit the { get; } and add readonly 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:

    • preventing modification of the collection as a whole (such as by removing or adding elements, or by assigning a new collection to the variable).
    • preventing modification of individual elements.
      (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 class ReadOnlyCollection, does not even support indexed access, making it fundamentally unsuitable for providing array-like access.)
你的往事 2024-10-26 16:56:40

如果在 IReadOnlyList 接口后面声明一个数组,您将获得一个具有在运行时声明的常量值的常量数组:

public readonly IReadOnlyList<string> Titles = new [] {"German", "Spanish", "Corrects", "Wrongs" };

在 .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:

public readonly IReadOnlyList<string> Titles = new [] {"German", "Spanish", "Corrects", "Wrongs" };

Available in .NET 4.5 and higher.

稚然 2024-10-26 16:56:40

我相信你只能将其设置为只读。

I believe you can only make it readonly.

非要怀念 2024-10-26 16:56:40

根据我的需要,我定义了 static 数组,而不是不可能的 const 并且它可以工作:
public static string[] Titles = { "德语", "西班牙语", "正确", "错误" };

For my needs I define static array, instead of impossible const and it works:
public static string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };

懷念過去 2024-10-26 16:56:40

这是一种执行您想要的操作的方法:

using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;

public ReadOnlyCollection<string> Titles { get { return new List<string> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();}}

它与执行只读数组非常相似。

This is a way to do what you want:

using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;

public ReadOnlyCollection<string> Titles { get { return new List<string> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();}}

It is very similar to doing a readonly array.

灼痛 2024-10-26 16:56:40

数组可能是只能在以下位置进行评估的事物之一
运行时。常量必须在编译时求值。尝试使用“只读”
而不是“常量”。

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

聊慰 2024-10-26 16:56:40

快速解决方法,以防对某人有帮助。我需要一个 string[] 来作为属性的参数(在某些理论中为测试用例传递内联数据)。 readonly 在这里没有帮助。但是,我最终做了:

const string foo = "a|b|c";

[InlineData(foo)]
public void Test(string fooString)
{
    var foo = fooString.Split("|"); // foo == {"a","b","c"}
    ...
}

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:

const string foo = "a|b|c";

[InlineData(foo)]
public void Test(string fooString)
{
    var foo = fooString.Split("|"); // foo == {"a","b","c"}
    ...
}
我不会写诗 2024-10-26 16:56:40

最佳替代方案:

public static readonly byte[] ZeroHash = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

Best alternative:

public static readonly byte[] ZeroHash = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
国产ˉ祖宗 2024-10-26 16:56:40

作为替代方案,要解决只读数组的元素可修改问题,您可以使用静态属性。 (单个元素仍然可以更改,但这些更改只会在数组的本地副本上进行。)

public static string[] Titles 
{
    get
    {
        return new string[] { "German", "Spanish", "Corrects", "Wrongs"};
    }
}

当然,这不会特别有效,因为每次都会创建一个新的字符串数组。

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.)

public static string[] Titles 
{
    get
    {
        return new string[] { "German", "Spanish", "Corrects", "Wrongs"};
    }
}

Of course, this will not be particularly efficient as a new string array is created each time.

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