【问题标题】:Workaround to pass "256" as a parameter using a byte使用字节将“256”作为参数传递的解决方法
【发布时间】:2014-04-26 10:57:24
【问题描述】:

我正在创建一个包含我用来缓存计算值的私有数组的类。我想将元素的数量限制为最大 256,因为这是使用 byte 索引的索引器可以访问的最大元素数量;我还需要这个数字相当小,所以这行得通。

但是!它必须作为构造函数中的参数传递,因为客户端代码将确定它的大小。但是,如果我将 byte 作为参数,则最大值为 255;我了解这是为什么以及如何发生,但我无法找出最佳解决方法。

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

我可以将它设为 byte?,如果它为 null,则使用 256 个元素,但这似乎是任意的(尽管它肯定会起作用)。我可以看到的另一种选择是使用 int 并以某种方式限制值,但将其公开为 int 可能会给用户错误的代码意图。

编辑:将“spritesToIndex”更改为“spriteCount”以使其更清晰。值得一提的是,这是我正在实现的接口:

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

【问题讨论】:

    标签: c# arrays byte


    【解决方案1】:

    我可以看到的另一种选择是使用 int 并以某种方式限制值

    使用int 正是我会做的。

    但将其公开为 int 可能会给用户错误的代码意图。

    所以要明确意图,让用户不可能得到错误的想法:

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

    即使用户在任何时候都知道spriteCount 可以是 1000,但在尝试之后,这个想法很快就会非常消失。

    我重命名了spriteToIndex 以回应 Richard Schneider 的 cmets,他们对变量名称的不同解释是完全可以理解的。其中的“索引”一词可以理解为暗示该值必须是索引,而不是精灵的总数。

    【讨论】:

    • 在这里显式揭示了一个有趣的结论:它接受 257 个有效输入,而不是 256 个,因此输入必须大于 byte。但是,仅当 0 实际上是合法值时才会出现这种情况。如果 0 实际上不合法,那么 RichardSchneider 的答案的优点是编译时无法传入非法值。
    • @Joe:这正是最初提出这个问题的原因。我原本打算将 0 设为合法值,因为 0 元素的数组是有效的 C#。
    【解决方案2】:

    我建议您让您的构造函数将计数作为 int 参数,并通过文档和参数命名清楚地表明它不应超过 256。您可以通过抛出 ArgumentOutOfRangeException 来保证超出这个范围。

    就我个人而言,我更习惯于提供范围参数为ints——至少对我来说,在这里使用byte 感觉不正统。

    【讨论】:

    • 这不是非正统的 - 类型的存在是有原因的,并且使用它作为参数没有任何限制。您可能不习惯使用它,但没有与之相关的代码异味。
    【解决方案3】:
    1. _values 的初始化程序错误。您应该添加 1 spritesToIndex
    2. Rectangle 的构造函数参数是int

    所以以下应该可以工作:

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

    @hvd 有一个很好的观点。构造函数应该接受int 类型并且只接受throw ArgumentOutOfRange

    【讨论】:

    • 如果spritesToIndex是需要可索引的精灵总数,并且第一个精灵索引为0,那么new Rectangle[spritesToIndex]是正确的。但是您的答案提供了一个有趣的选择。将spritesToIndex 更改为maxSpriteIndex(并像现在一样添加一个)将允许将其保留为一个字节。
    • @hvd,如果我们将 arg 重命名为 maxSprites,您的答案会更好。我只是在黑客攻击。
    • 哦!现在我看看你是怎么读的。我读了“spritesToIndex”,就像 OP 可能打算的那样,它是“sprites to index”(其中“to index”是不定式),但它也可以读作“spritesTo index”(“spritesTo 的索引”),并且确实会导致你的答案。将编辑我的答案,感谢您的评论。
    • 对不起,我不清楚,编辑以使我的代码意图更好。我还添加了我正在实现的界面;有了这个,应该很明显所有的 Rectangle 对象都会自动生成。
    【解决方案4】:

    C#Byte 类型是一个 8 位容器,可以容纳 0 到 255 范围内的值,这意味着它具有 256 个值的容量。如果您的应用程序需要跟踪 256 个索引项,这就足够了,因为数组的第一个元素是“零”元素(即 foo[0] 是第一个元素)。

    但是,如果您确实需要跟踪 256 个离散项目,其中它们具有正标识符值并且零不适合作为第一个值,那么 Byte 将不够用。您将不得不使用容量更大的类型,例如 ShortInt,并在代码中添加边界检查以将其值范围限制为 1-256。

    【讨论】:

    • 我将使用 0,问题是我不能接受 byte 作为参数并从中创建一个 256 元素数组(因为 Byte.MaxValue 是 255,而不是 256,尽管有是 256 个可能的值)。
    • 是的,你可以 - 0-255 是 256 个值(或者,如果你愿意,foo[0] - foo[255] 是一个包含 256 个元素的 foo 数组)。
    • 是的,但是我不能使用字节作为参数来声明一个包含 256 个元素的数组,因为……尽管有 256 个唯一值,但可能的最高值是 255。跨度>
    • 好的,你不能传递实际值 256 - 但是如果你传递 255 并用该值实例化数组,你会得到一个包含 256 个元素的数组。所以你作为参数传递的值比你想要的数组中元素的数量少一。
    猜你喜欢
    • 1970-01-01
    • 2010-11-16
    • 1970-01-01
    • 2015-11-11
    • 1970-01-01
    • 2018-09-09
    • 2019-02-22
    • 2012-06-08
    相关资源
    最近更新 更多