繁体   English   中英

声明一个常量数组

[英]Declare a const array

是否可以编写类似于以下内容的内容?

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

是的,但您需要将其声明为readonly而不是const

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

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

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

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

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

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

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

考虑使用枚举,如 Cody 建议的,或 IList。

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

您不能创建“const”数组,因为数组是对象,只能在运行时创建,而 const 实体在编译时解析。

您可以做的是将您的数组声明为“只读”。 除了可以在运行时设置值之外,这与 const 具有相同的效果。 它只能设置一次,此后它是只读(即常量)值。

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

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

另请参阅: C#:新的和改进的 C# 6.0 (特别是“Expression Bodied Functions and Properties”一章)

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

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

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

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

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

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

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

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

有些人建议使用 static 或 readonly 来模拟如果可以创建 const 数组时会看到的行为。 这些有一些副作用,对普通读者来说可能并不明显。

要真正获得 const 数组,需要更新 C# 和 MSIL 底层代码,以允许从数组读取,但不允许写入。

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

using System.Collections.ObjectModel;

// ...

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

注意:鉴于集合在概念上是常量,在级别将其声明为static可能是有意义的。

以上:

  • 使用数组初始化属性的隐式支持字段一次

    • 请注意{ get; } { get; } - 即,只声明一个属性getter - 是什么使属性本身隐式只读(试图将readonly{ get; }结合实际上是一个语法错误)。

    • 或者,您可以省略{ get; } { get; }并添加readonly创建领域,而不是一个属性,如问题,但暴露公共数据成员的属性,而不是场是一个好习惯的形成。

  • 创建一个类似数组的结构(允许索引访问),它是真正且健壮的只读(概念上不变,一旦创建),两者都涉及:

    • 防止整个集合的修改(例如通过删除或添加元素,或通过将新集合分配给变量)。
    • 防止修改单个元素
      (即使是间接修改也是不可能的 - 与IReadOnlyList<T>解决方案不同,其中(string[])可用于获得对元素的写访问权限,如mjepsen 的有用答案所示
      相同的漏洞适用于IReadOnlyCollection<T>接口,尽管名称与ReadOnlyCollection相似,但它甚至不支持索引访问,因此从根本上不适合提供类似数组的访问。)

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

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

在 .NET 4.5 及更高版本中可用。

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

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

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

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

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

需要 System.Collections.Immutable NuGet 参考

https://msdn.microsoft.com/en-us/library/mt452182(v=vs.111).aspx

为了我的需要,我定义了static数组,而不是不可能的const ,它可以工作: public static string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };

这是一种做你想做的事情的方法:

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

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

它与做一个只读数组非常相似。

我相信你只能让它只读。

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

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

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

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

最佳选择:

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 };

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM