0

I have a struct and an integer variable on it. My variable value must be between 1200 and 1599. but in default constructor I have no control in value of variable. How can I do this in my 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;
    }
}
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
mohammad
  • 1,248
  • 3
  • 15
  • 27

6 Answers6

2

Use a property with a backing field:

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
}

I combined the property with my setter and Damien_The_Unbeliever's getter to get the initial state of x right. I also agree with Tim about constants for the "magic numbers" and added that too. So please give this two also credit for "my answer".

Also as DatVM already said: Public fields/properties should start with a capital letter according to the common C# naming guidlines. This also enalbes you to use the same name for the backing field, but starting with a small letter (I personally do NOT like the ugly _)...

And last but not least: Please read rexcfnghk's answer, even if it is not really an answer, as he is also absolutely correct.

Christoph Fink
  • 22,727
  • 9
  • 68
  • 113
2

Another variant on using a property and a private backing field:

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

Which ensures that the default constructed value is "in range".

But any variant is going to introduce some overhead, so it's up to you whether this is acceptable.

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
1

My variable value must be between 1200 and 1599

In C#, you cannot define your own default constructor for structs. If you have an array of MyStruct, like var myArray = new MyStruct[5], the default constructor of MyStruct will be invoked and elements in myArray will have all have x equals to 0, which is invalid according to your requirement.

Which is why I believe you have an incorrectly designed struct. According to the Framework Design Guidelines

DO ensure that a state where all instance data is set to zero, false, or null (as appropriate) is valid.

This prevents accidental creation of invalid instances when an array of the structs is created.

If you need argument validation when your struct's default constructor is invoked, use a class instead.

Also, your current design of MyStruct makes it mutable. please take a look on why Mutable structs are evil.

Community
  • 1
  • 1
rexcfnghk
  • 14,435
  • 1
  • 30
  • 57
  • This should be a comment as it's not a direct answer to the question, but rather promoting good design in the context of the question. – aevitas Apr 29 '14 at 07:38
  • @aevitas, OP is asking for argument validation in default constructor, which is not possible in C# because C# does not allow `struct`s to have default constructors. I provided a solution to use `class` instead, how is it not a direct answer to the question? – rexcfnghk Apr 29 '14 at 07:40
  • No, if you take a look at the revisions, I had given my answer in my very first submission. – rexcfnghk Apr 29 '14 at 07:53
1

I would use properties with getter and setter and a private backing field where you can implement this logic or even throw an ArgumentOutOfRangeException if the value is outside of the boundaries.

Here is an example:

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

It's good practices to always use properties even if you don't need to restrict the access in the first place. Then it's easier to implement such a logic if you need.

One final note: i would suggest to use a class instead of struct.

Community
  • 1
  • 1
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
0

You should change x into property instead:

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: as for C# naming convention, it should be called X (capital) instead of x

Luke Vo
  • 17,859
  • 21
  • 105
  • 181
0

A struct can be made to have a default value if, rather than using a public field, one uses a private field and a public property which transforms the field's value in such a way that its default value will map to the desired default for the structure. For example, you could have a backing field int _x_minus_1200; and have a property getter which returns _x_minus_1200 + 1200. I'm not hugely keen on such approaches (generally I prefer for structures to have public fields and behave like structures, and have the meaning and validation of structure fields be a function of the code that uses the structures) but in some cases they can be helpful.

supercat
  • 77,689
  • 9
  • 166
  • 211