你能在C#中定义一个预先指定大小的数组吗?

时间:2016-03-04 18:40:31

标签: c# .net

我在这里尝试做的事情应该通过下面的代码来显而易见

public class RangeInfo
{
    public int[2] Range { set; }
    public string Text { set; }
}

public readonly RangeInfo[4] Ranges = new RangeInfo[4] { 
    new RangeInfo { Range = new int[2] {Int32.MinValue,70}, Text = "..." },
    new RangeInfo { Range = new int[2] {70,80}, Text = "..." },
    new RangeInfo { Range = new int[2] {80,90}, Text = "..."},
    new RangeInfo { Range = new int[2] {90,Int32.MaxValue}, Text = "..." }
};

但是我遇到了很多错误,比如

  

无法在变量声明中指定数组大小

on public int[2]

  

预期,类,代表,枚举或结构

on RangeInfo[4]

我做错了什么?

3 个答案:

答案 0 :(得分:7)

Length是数组实例的属性,不是类型的一部分。数组变量仅包含指向数组的指针。因此,字段,属性和其他变量声明与长度无关。您只能在实例化数组时指定长度,而不能在声明变量时指定长度。

如果您需要数组具有特定长度,则属性设置器可以在运行时检查长度,如果长度错误则抛出异常。但是,在编译时无法强制执行此操作。

更易于维护的解决方案可能是根本不使用数组,而是为数组中当前表示的每个值创建一个具有单独属性的类。这假设特定指数的值具有不同的含义。如果数组真的只代表一组值,那么你最好使用List。见https://en.wikipedia.org/wiki/Zero_one_infinity_rule

答案 1 :(得分:5)

数组长度不是类型签名的一部分,因此长度为2的数组的类型与长度为3的数组的类型相同。唯一的类型是int[],表示任意长度的int数组

如果你来自C ++,这可能会让人感到困惑,因为数组可能是"在行中" 参考。在C#数组中,就像其他引用类型一样(除非明确告知为stackalloc)堆已分配,因此您的变量只是指向堆上数组的指针。

如果你想限制大小,你需要在属性的setter中约束它(或者最好 - 在你的类的构造函数中,从那时起你可以使类不可变)。

public class RangeInfo
{
   public RangeInfo(IList<int> range, string txt)
   {
      if (range == null || range.Count != 2)
         throw new ArgumentException(..);
      Range = range.ToArray();
      Info = txt;
   }
   public int[] Range { get; private set; }
   public string Info { get; private set; }
}

然而,对于这种类型的构造,我宁愿只将两个int传递给ctor,并且有两个int字段(这样你就不必堆堆分配一个数组)。你也可以使用元组或声明一个int对类。您仍然可以通过返回new[]{a,b}将这两个内部int字段公开为数组。

顺便说一句:固定大小的数组确实存在于C#中,但主要用于互操作。为了调用一些需要64个连续32位整数的C API,声明这样的结构将是非常愚蠢的:

struct FooStruct
{
    int int0;
    int int1;
    ..
    int int63;
}

因此,可以创建一个仅仅模仿上述内容的fixed int[64]

[StructLayout(LayoutKind.Sequential, Pack = 1)]
unsafe struct FooStruct
{
    fixed int[64] data;
}

答案 2 :(得分:1)

我将您的代码更改为编译,但保持接近您最初尝试实现的目标。

    public class RangeInfo
    {
        private string _text;
        private int[] _range;
        public int[] Range
        {
            set
            {
                if (value.Length != 2)
                    throw new Exception("Length must be 2.");
                if (_range == null)
                    _range = new int[2];

                _range[0] = value[0];
                _range[1] = value[1];
            }
            get
            {
                return _range;
            }
        }
        public string Text { set { _text = value; } get { return _text; } }
    }

    static public readonly RangeInfo[] Ranges = new RangeInfo[4] { 
                    new RangeInfo { Range = new int[] {Int32.MinValue,70}, Text = "..." },
                    new RangeInfo { Range = new int[] {70,80}, Text = "..." },
                    new RangeInfo { Range = new int[] {80,90}, Text = "..."},
                    new RangeInfo { Range = new int[] {90,Int32.MaxValue}, Text = "..." }
            };