Subpar Web Dev
Subpar Web Dev

Reputation: 3260

Can you define an array with a pre-specified size in C#?

What I'm trying to do here should be obvious by the below code

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 = "..." }
};

but I'm getting tons of errors like

Array size cannot be specified in a variable declaration

on public int[2],

Expected, class, delegate, enum or struct

on RangeInfo[4]

What am I doing wrong?

Upvotes: 6

Views: 14387

Answers (3)

Anders Forsgren
Anders Forsgren

Reputation: 11101

Array lengths are not part of the type signature, so the type of an array of length 2 is the same as the type of an array of length 3. The only type is int[] meaning int array of any length.

This may be confusing if you come from C++ where an array can be "in line" or a reference. In C# arrays just like other reference types are normally (unless explicitly told to be stackalloc) heap allocated, so your variable is just a pointer to an array on the heap.

If you want to constrain the size you would need to constrain it in the setter of the property (or preferably -- in the constructor of your class, since then you can make the class immutable).

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

However, with this type of construction I'd rather just pass in two ints to the ctor, and have two int fields (That way you don't have to heap allocate an array).You could also use a tuple or declare an int pair class. You could still expose the two internal int fields as an array by returning new[]{a,b}.

As an aside: fixed size arrays do exist in C#, but mainly for interop. It would be pretty silly to declare structs like this in order to call some C API that wants 64 consecutive 32bit ints:

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

So instead it's possible to create a fixed int[64] which just emulates the above.

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

Upvotes: 10

Erik
Erik

Reputation: 519

I changed your code to compile but stay close to what you were trying to achieve originally.

    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 = "..." }
            };

Upvotes: 2

hypehuman
hypehuman

Reputation: 1369

Length is a property of an array instance, not part of the type. An array variable merely contains a pointer to an array. Therefore fields, properties, and other variable declarations are agnostic of the length. You can only specify the length when instantiating an array, not when declaring variables.

If you need your arrays to have a particular length, your property setters can check the length at runtime and throw an exception if the length is wrong. However, there is no way to enforce this at compile time.

A more maintainable solution might be to not use arrays at all, and instead create a class with a separate property for each value currently represented in your arrays. This assumes that the values at particular indices have different meanings. If the array really is representing just a set of values, then you're probably better off using a List. See https://en.wikipedia.org/wiki/Zero_one_infinity_rule

Upvotes: 7

Related Questions