Question

I'm making a class which contains a private array that I am using to cache calculated values. I want to limit the number of elements to 256 at maximum, since that is the maximum number of elements an indexer that uses a byte index can access; I also need the number to be fairly small, so this works.

However! It must be passed as an argument in the constructor, since the client code would determine just how big it would be. But, if I take a byte as an argument, the maximum is 255; I understand why and how this is, but I cannot figure out the best workaround.

public class Spritesheet
{
    private Rectangle[] _values;
    public Spritesheet(byte spriteCount)
    {
        _values = new Rectangle[spriteCount]; // But this needs to store 256 values at most...
    }
}

I could make it a byte? and if it's null, use 256 elements, but that seems arbitrary (although it would certainly work). The other alternative I can see would be using an int and clamping the value somehow, but exposing it as an int might give the user the wrong intent of the code.

EDIT: Changed "spritesToIndex" to "spriteCount" to make it clearer. And for what it's worth, this is the interface I made that I'm implementing:

public interface ISpritesheet
{
    Texture2D Texture { get; }

    byte Sprites { get; }
    byte SpritesPerRow { get; }

    Point Size { get; }
    Point Spacing { get; }
    Point Offset { get; }

    Rectangle this[byte index] { get; }
}
Was it helpful?

Solution

The other alternative I can see would be using an int and clamping the value somehow

Using int is exactly what I would do.

but exposing it as an int might give the user the wrong intent of the code.

So make the intent so explicit that the user cannot possibly get the wrong idea:

public class Spritesheet
{
  public Spritesheet(int spriteCount)
  {
    if (spriteCount < 0 || spriteCount > 256)
      throw new ArgumentOutOfRangeException ("spriteCount", "Number of sprites must be between 0 and 256 (inclusive)");
    // ...
  }
}

Even if the user at any point gets the idea that spriteCount can be 1000, that idea will fade very quickly after trying it.

I renamed spriteToIndex in response to Richard Schneider's comments, who quite understandably interpreted the meaning of the variable name differently. The word "Index" in it could be read as suggesting that the value must be an index, rather than the total number of sprites.

OTHER TIPS

I'd recommend you have your constructor take the count as an int argument, and make it obvious through documentation and parameter naming that this should not exceed 256. You can guarantee that by throwing an ArgumentOutOfRangeException for values that exceed that range.

Personally, I'm more used to supplying range parameters as ints anyway -- using a byte here feels unorthodox, at least to me.

  1. your initialiser for _values is wrong. You should add 1 spritesToIndex.
  2. the constructor args to Rectangle is an int.

So the following should work:

_values = new Rectangle[(int)spritesToIndex + 1];

@hvd has a good point. The constructor should accept an int type and just throw ArgumentOutOfRange.

The C# Byte type is an 8-bit container which can hold values in the range 0 to 255, which means it has a 256-value capacity. If your application needs to track 256 indexed items, this will suffice because the first element of an array is the 'zero-th' element (i.e. foo[0] is the first element).

However, if you actually need to track 256 discrete items where they have a positive identifier value and zero is not appropriate as the first value, a Byte will not suffice. You will instead have to use a type with a larger capacity such as Short or Int, and add bounds checks in your code to limit their value range to 1-256.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top