KalC
KalC

Reputation: 1800

Calling a structure method inside a non-default structure constructor

I have this very simple example that I am using to learn structs in C#:

struct ScreenPosition
{
    // These are the two private members of the structure 
    private int x; 
    private int y;

    private int RangeCheckedX(int xPos)
    {
        if (xPos < 0 || xPos > 1280)
        {
            throw new ArgumentOutOfRangeException("X");
        }
        return xPos;
    }

    private int RangeCheckedY(int yPos)
    {
        if (yPos < 0 || yPos > 1024)
        {
            throw new ArgumentOutOfRangeException("Y");
        }
        return yPos;
    }

    // Declaring the non-default constructor
    public ScreenPosition(int X, int Y)
    {
        this.x = RangeCheckedX(X); // ERROR HERE
        this.y = RangeCheckedY(Y); // ERROR HERE
    }

    // Declaring  the property X - Follows a syntax. See the C# quick reference sheet 
    public int X
    {
        get
        {
            return this.x;
        }

        set
        {
            this.x = RangeCheckedX(value);
        }
    }
    // Declaring  the property X - Follows a syntax. See the C# quick reference sheet 
    public int Y
    {
        get
        {
            return this.y;
        }

        set
        {
            this.y = RangeCheckedY(value);
        }
    }
}

I am getting this error at the "ERROR HERE" comment lines:

The 'this' object cannot be used before all of its fields are assigned to

Is it illegal to call a structure method in the non-default constructor to assign values to the structure members?

Upvotes: 3

Views: 2182

Answers (4)

GBegen
GBegen

Reputation: 6157

You can make those methods static and it will work, but you cannot call a non-static method until all the fields have been assigned.

Upvotes: 6

Jeffrey L Whitledge
Jeffrey L Whitledge

Reputation: 59463

You could set each of the fields to zero before validating the inputs. This makes some sense because the default constructer will set them to zero anyway, so that's a case that has to be handled in your program anyway. Once the values are set, you can call whatever methods you want, even in the constructor.

But the correct solution is what everyone else is saying: make the range checks static methods. In fact, in this case they are pure functions (no side effects and operating only on the parameters rather than static or instance fields). Pure functions can always be static. And static pure functions are chocolate-covered-awesome from the perspectives of debugging, multi-threading, performance, etc.

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1500495

GBegen has the right idea - make the range check methods static.

Not only will this fix the problem, but it'll make the code clearer, too: the methods don't rely on the state of the structure at all, and they're not acting polymorphically, so they shouldn't be instance methods.

Upvotes: 2

Blounty
Blounty

Reputation: 3358

It is not allowed to call methods on structs until all fields (properties) are populated.

I know its a hack but this would work.

 struct ScreenPosition
{
    // These are the two private members of the structure 
    private int x;
    private int y;

    private int RangeCheckedX(int xPos)
    {
        if (xPos < 0 || xPos > 1280)
        {
            throw new ArgumentOutOfRangeException("X");
        }
        return xPos;
    }

    private int RangeCheckedY(int yPos)
    {
        if (yPos < 0 || yPos > 1024)
        {
            throw new ArgumentOutOfRangeException("Y");
        }
        return yPos;
    }

    // Declaring the non-default constructor
    public ScreenPosition(int X, int Y)
    {
        this.x = X; 
        this.y = Y; 
        this.x = RangeCheckedX(X);
        this.y = RangeCheckedY(Y);
    }

    // Declaring  the property X - Follows a syntax. See the C# quick reference sheet 
    public int X
    {
        get
        {
            return this.x;
        }

        set
        {
            this.x = RangeCheckedX(value);
        }
    }
    // Declaring  the property X - Follows a syntax. See the C# quick reference sheet 
    public int Y
    {
        get
        {
            return this.y;
        }

        set
        {
            this.y = RangeCheckedY(value);
        }
    }
}

Upvotes: 2

Related Questions