是否可以编写类似于以下内容的内容?
public const string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
是否可以编写类似于以下内容的内容?
public const string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
Answers:
是的,但是您需要声明它readonly
而不是const
:
public static readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
原因是 const
只能应用于其值在编译时已知的字段。您显示的数组初始值设定项在C#中不是常量表达式,因此会产生编译器错误。
声明它readonly
解决了这个问题,因为该值要到运行时才初始化(尽管可以保证在第一次使用该数组之前就已对其进行了初始化)。
根据最终要实现的目标,您还可以考虑声明一个枚举:
public enum Titles { German, Spanish, Corrects, Wrongs };
readonly static
具有所请求语义的任何相似之处。
static
来说,不需要使其工作,它只是增加了引用的可能性而Titles
没有实例,但是消除了为不同实例更改值的可能性(例如,可以使构造函数具有参数,具体取决于您更改该readonly
字段的值)。
您可以将array声明为readonly
,但是请记住,可以更改readonly
array的元素。
public readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
...
Titles[0] = "bla";
根据Cody的建议,考虑使用enum或IList。
public readonly IList<string> ITitles = new List<string> {"German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();
const
不是readonly
……
您无法创建'const'数组,因为数组是对象,只能在运行时创建,而const实体则在编译时解析。
您可以做的是将数组声明为“只读”。除了可以在运行时设置值之外,这与const具有相同的作用。它只能设置一次,此后是只读(即const)值。
const int[] a = null;
不是很有用,但实际上是数组常量的实例。
从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";
Titles[0]
例如,如果您分配给,则不会出现编译错误-实际上,分配尝试被悄悄地忽略了。再加上每次重新创建阵列的效率低下,我想知道这种方法是否值得展示。相比之下,第二种方法是有效的,您必须竭尽全力来克服不变性。
一个.NET框架V4.5 +解决方案是提高了tdbeckett的回答:
using System.Collections.ObjectModel;
// ...
public ReadOnlyCollection<string> Titles { get; } = new ReadOnlyCollection<string>(
new string[] { "German", "Spanish", "Corrects", "Wrongs" }
);
注意:鉴于集合在概念上是恒定的,因此static
使其在类级别进行声明可能很有意义。
以上:
使用数组一次初始化属性的隐式后备字段。
注意{ get; }
-即,仅声明属性getter-是使属性本身隐式只读的原因(尝试readonly
与之合并{ get; }
实际上是语法错误)。
或者,您可以省略{ get; }
和添加readonly
以创建字段而不是属性,就像在问题中一样,但是将公共数据成员公开为属性而不是字段是一种好习惯。
创建一个类似于数组的结构(允许索引访问),该结构真正且健壮地为只读(概念上是常量,一旦创建),就以下方面而言:
IReadOnlyList<T>
解决方案,其中一个(string[])
投可以用来获得对要素的写入权限,如图mjepsen的帮助的解答。IReadOnlyCollection<T>
接口,其中,尽管在名称相似进行分类 ReadOnlyCollection
,甚至不支持索引访问,这使其从根本上不适合提供类似数组的访问。)IReadOnlyCollection
它不支持索引访问,因此不能在这里使用。此外,像IReadOnlyList
(确实具有索引访问权)一样,它也很容易通过回退到来进行元素操作string[]
。换句话说:(ReadOnlyCollection
您不能将其转换为字符串数组)是最可靠的解决方案。不使用吸气剂是一种选择(我已经更新了答案以指出这一点),但是对于公共数据,最好保留一个属性。
您可以采用另一种方法:定义一个常量字符串来表示您的数组,然后在需要时将其拆分为一个数组,例如
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/zh-CN/library/mt452182(v=vs.111).aspx
这是一种执行所需操作的方法:
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 readonly ReadOnlyCollection<String> Titles = new List<String> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();
; 如果您将其设为ReadOnlyCollection,则无需在每次检索时都重新创建列表。