为结构中的字段定义最大值和最小值

本文关键字:最大值 最小值 定义 字段 结构 | 更新日期: 2023-09-27 18:00:54

我有一个struct和一个整数变量。我的变量值必须在1200到1599之间。但在默认构造函数中,我无法控制变量的值。如何在struct中执行此操作?

struct MyStruct
{
    public int x;
    public MyStruct(int x)
    {
         if(x>1599)
              this.x=1599;
         else if(x<1200)
              this.x=1200;
         else
              this.x=x;
    }
}

为结构中的字段定义最大值和最小值

关于使用属性和私有后台字段的另一个变体:

struct MyStruct
{
    private int x;
    public MyStruct(int x)
    {
        if (x > 1599)
            this.x = 399;
        else if (x < 1200)
            this.x = 0;
        else
            this.x = x - 1200;
    }
    public int X { get { return x+1200; } }
}

这样可以确保默认构造的值"在范围内"。

但任何变体都会引入一些开销,所以这是否可以接受取决于您。

使用带有支持字段的属性:

struct MyStruct
{
    private const int MIN_VALUE = 1200;
    private const int MAX_VALUE = 1599;
    private int x;
    public int X 
    {
        get { return x + MIN_VALUE; }
        set
        {
            if(value > MAX_VALUE)
                x = MAX_VALUE;
            else if(value < MIN_VALUE)
                x = MIN_VALUE;
            else
                x = value;
            x -= MIN_VALUE;
        }
    }
    // constructor is not really needed anymore, but can still be added
}

我将属性与我的setter和Damien_the_Unbeliever的getter相结合,以获得正确的x的初始状态。我也同意蒂姆关于"幻数"常数的观点,并补充了这一点。因此,请将这两个也归功于"我的答案"。

正如DatVM已经说过的:根据常见的C#命名指南,公共字段/属性应该以大写字母开头。这也允许你使用相同的名字作为背景字段,但以一个小字母开头(我个人不喜欢丑陋的_(。。。

最后但同样重要的是:请阅读rexcfnghk的答案,即使这不是一个真正的答案,因为他也是绝对正确的。

我的变量值必须在1200和1599 之间

在C#中,您不能为structs定义自己的默认构造函数。如果您有一个MyStruct的数组,如var myArray = new MyStruct[5],则会调用MyStruct的默认构造函数,并且myArray中的元素都具有等于0的x,根据您的要求,这是无效的。

这就是为什么我认为你有一个设计错误的struct。根据框架设计指南

DO确保所有实例数据设置为零、假或空(视情况而定(的状态有效。

这样可以防止在创建结构数组时意外创建无效实例。

如果在调用struct的默认构造函数时需要参数验证,请改用class

此外,您当前的MyStruct设计使其可变。请看一下为什么可变结构是邪恶的。

我会使用getter和setter的属性以及一个私有的支持字段,在那里您可以实现这个逻辑,甚至在值超出边界时抛出ArgumentOutOfRangeException

这里有一个例子:

struct MyStruct
{
    private const int MIN_VALUE = 1200;
    private const int  MAX_VALUE = 1599;
    private int _X;
    public int X
    {
        get { return _X; }
        set { _X = checkBoundaries(value); }
    }
    private static int checkBoundaries(int x)
    {
        if (x > MAX_VALUE)
            return MAX_VALUE;
        else if (x < MIN_VALUE)
            return MIN_VALUE;
        else
            return x;
    }
    public MyStruct(int x)
    {
        _X = checkBoundaries(x);
    }
}

即使一开始不需要限制访问,也要始终使用属性,这是一种良好的做法。如果需要的话,实现这样的逻辑会更容易。

最后一点:我建议使用类而不是结构。

  • 不能在结构中定义默认构造函数,因此不能阻止使用默认值0初始化_X
  • 不能用内联的最小值初始化_X,因为结构中也不允许这样做
  • 如果你的类型越来越复杂,并且你有这样的规则,这是一个很好的指标,表明类会更合适

您应该将x改为property

private int _x;
public int x {
    get
    {
        return _x;
    }
    set
    {
        _x = value;
        if (_x > 1599)
        {
            _x = 1599
        }
        else if (_x < 1200)
        {
            _x = 1200
        }
    }
}

p.S:对于C#命名约定,应该称为X(大写(,而不是x

如果不是使用公共字段,而是使用私有字段和公共属性来转换字段的值,从而使其默认值映射到结构所需的默认值,则可以使结构具有默认值。例如,您可以有一个后备字段int _x_minus_1200;,并有一个返回_x_minus_1200 + 1200的属性getter。我对这种方法不太感兴趣(通常我更喜欢结构具有公共字段,表现得像结构,并将结构字段的含义和验证作为使用结构的代码的函数(,但在某些情况下,它们可能会有所帮助。