声明一个const数组
是否有可能写类似于以下的东西?
public const string[] Titles = {"German", "Spanish", "Corrects", "Wrongs"};
是的,但你需要声明它readonly
而不是const
:
public static readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
原因是const
只能应用于编译时已知值的字段。 你显示的数组初始值设定项不是C#中的常量expression式,所以会产生编译器错误。
声明它readonly
解决了这个问题,因为值直到运行时才被初始化(虽然它保证在第一次使用数组之前被初始化)。
根据你最终想要达到什么,你也可以考虑声明一个枚举:
public enum Titles { German, Spanish, Corrects, Wrongs };
您可以将数组声明为readonly
,但请记住,您可以更改readonly
数组的元素。
public readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" }; ... Titles[0] = "bla";
考虑使用枚举,如科迪build议,或IList。
public readonly IList<string> ITitles = new List<string> {"German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();
你不能创build一个'const'数组,因为数组是对象,只能在运行时创build,而const实体在编译时parsing。
你可以做的是将你的数组声明为“只读”。 这与const的效果相同,除了可以在运行时设置该值。 它只能被设置一次,并且是一个只读(即const)值。
你可以采取一种不同的方法:定义一个常量string来表示你的数组,然后当你需要的时候把string拆分成一个数组
const string DefaultDistances = "5,10,15,20,25,30,40,50"; public static readonly string[] distances = DefaultDistances.Split(',');
这种方法给你一个常量,可以存储在configuration中,并在需要时转换为数组。
阿拉斯泰尔
为我的需要我定义static
数组,而不是不可能的const
,它的工作原理: public static string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
从C#6开始,你可以这样写:
public static string[] Titles => new string[] { "German", "Spanish", "Corrects", "Wrongs" };
另请参阅: C#:新增和改进的C#6.0 (特别是“expression式主体函数和属性”一章)
这将使一个只读的静态属性,但它仍然会允许你改变返回的数组的内容,但是当你再次调用属性,你会得到原来的,不变的数组了。
澄清,这个代码是相同的(或实际上是一个简写):
public static string[] Titles { get { return new string[] { "German", "Spanish", "Corrects", "Wrongs" }; } }
请注意,这种方法有一个缺点:新的数组实际上是在每个引用上实例化的,所以如果你使用的是一个非常大的数组,那么这可能不是最有效的解决scheme。 但是如果你重新使用相同的数组(例如把它放在一个私有属性中),它将再次打开改变数组内容的可能性。
如果你想有一个不可变的数组(或列表),你也可以使用:
public static IReadOnlyList<string> Titles { get; } = new string[] { "German", "Spanish", "Corrects", "Wrongs" };
但是,这仍然有变化的风险,因为您仍然可以将其转换回string[]并更改内容,如下所示:
((string[]) Titles)[1] = "French";
.NET Framework v4.5 +解决scheme改进了tdbeckett的答案 :
using System.Collections.ObjectModel; // ... public ReadOnlyCollection<string> Titles { get; } = new ReadOnlyCollection<string>( new string[] { "German", "Spanish", "Corrects", "Wrongs" } );
注意:鉴于集合在概念上是恒定的,在类级别声明它可能是有意义的。
以上:
-
使用数组初始化属性的隐式后台字段 。
-
请注意
{ get; }
{ get; }
– 即只声明一个属性getter – 是什么使属性本身隐式只读(试图结合readonly
与{ get; }
实际上是一个语法错误)。 -
或者,你可以忽略
{ get; }
{ get; }
并添加readonly
来创build一个字段,而不是一个属性,在问题中,但暴露公共数据成员作为属性而不是字段是一个好习惯形成。
-
-
创build一个类似于数组的结构 (允许索引访问),这个结构是真正强健的只读 (概念上,常量,一旦创build)
- 防止对集合进行修改(例如通过删除或添加元素,或者将集合replace为整体)
- 防止修改个别元素。
(即使是间接修改也是不可能的 – 与IReadOnlyList<T>
解决scheme不同的是,可以使用(string[])
强制转换来获取对元素的写入权限,如mjepsen的有用答案所示 。
同样的漏洞也适用于IReadOnlyCollection<T>
接口,尽pipe名字与类ReadOnlyCollection
相似,但它甚至不支持索引访问,使得它基本上不适合提供类似数组的访问)。
这是一种做你想做的事的方法:
using System; using System.Collections.ObjectModel; using System.Collections.Generic; public ReadOnlyCollection<string> Titles { get { return new List<string> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();}}
这和做一个只读数组非常相似。
我相信你只能使它只读。
数组可能是那些只能在运行时进行评估的事情之一。 常量必须在编译时进行评估。 尝试使用“只读”而不是“const”。
另外,为了解决只读数组中的元素可修改问题,可以使用静态属性来代替。 (单个元素仍可以更改,但这些更改只能在数组的本地副本上进行。)
public static string[] Titles { get { return new string[] { "German", "Spanish", "Corrects", "Wrongs"}; } }
当然,每次创build一个新的string数组时,效率都不是很高。
如果你在IReadOnlyList接口后面声明一个数组,你会得到一个在运行时声明的具有常量值的常量数组:
public readonly IReadOnlyList<string> Titles = new [] {"German", "Spanish", "Corrects", "Wrongs" };
在.NET 4.5和更高版本中可用。