Question

I learn C# and try to understand the logic between static and Constructor right now. One thing I need ask you about an example which I will give at below. (please ignore the quality of code or how could be written better things, I just need to understand the logic which I am asking)

There are 2 classes named Computer and BaseType. Computer inherits from BaseType and I am taking instance from Computer class.

In short, I wanted to gave an ID number to "Id" field in BaseType Class increasingly (starting from 1 and then 2,3,4 etc when the Computer class' instance has been taken). As I do that, I realized something interesting and wanted to ask you this logic to you.

Lemme give the sample code.

Main() Class

       static void Main(string[] args)
    {
        Computer C1 = new Computer();
        Computer C2 = new Computer();
        Computer C3 = new Computer();}

Computer() Class

public class Computer : Product
{
    public string Cpu { get; set; }
    public string Ram { get; set; }
    public string VideoCard { get; set; }
}

BaseType() Class

public class BaseType
{
    static int counter = 1;
    private int _Id;

    public int Id
    {
        get
        {
            return _Id;
        }
        private set
        {

        }
    }

    public BaseType()
    {
        _Id = IdAssignment();
    }

    int IdAssignment()
    {
        return counter++;
    }

I put breakpoints to each instances as taken them, also to constructor method and IdAssignment() method. ("Computer C1 = new Computer();" and so on)

Question1: As I taking instance as "C1", I realized that counter is "2" cause it's 1 because it's static in the beginning and has counter++. But, in constructor method, "_Id" is getting "1" instead of "2" and it continues so on. Normally it's what I want but I don't know how this happening. This I want to ask first.

Question2: As I am doing it, I realized that "_Id" in contructor method is always "0" before taking the "IdAssignment()"'s value. Shouldn't it be normally "1" as I come to taking second instance (C2)? This I want to ask you secondly.

Thanks

Was it helpful?

Solution

First of all, you have static int counter = 1. Since we are talking about a static field, it will be allocated for all objects (a single field for all objects, not one per object). Futhermore, the runtime will ensure that the value counter will have a value of 1 set to it before you try to access it for the first time.

This is similar to having

public class BaseType
{
    static int counter;

    static BaseType()
    {
        counter = 1;
    }
// ...

Notice that is an static constructor. The static constructor will only run once per class, and that is it. It will run sometime before you access the class for the first time. You are not in control of when.


Second you have a constructor:

public BaseType()
{
    _Id = IdAssignment();
}

If you access _Id before the line _Id = IdAssignment() executes, you would see 0.

The runtime could optimize this away in a release build (there is no need to zero the memory if you do not read it before assigning to it).


Finally, we find in IdAssignment the following:

int IdAssignment()
{
    return counter++;
}

The line counter++ will increment counter. This is a postfix increment operator, as opposed to a prefix increment operator (++counter). They differ in that counter++ returns the value before the increment, and ++counter returns the value after the increment.

As we know, the first time we get there counter will have a value of 1. It is incremented to 2, however, the value returned is 1 (the value before the increment), this means that _Id in the constructor will get 1.


As I taking instance as "C1", I realized that counter is "2" cause it's 1 because it's static in the beginning and has counter++

counter is 2 because it was incremented in return counter++;.


But, in constructor method, "_Id" is getting "1" instead of "2" and it continues so on

This is because you are using the postfix increment operator:

return counter++;

It is equivalent to:

var tmp = counter;
counter++;
return tmp;

If this is not what you want, you could use the prefix increment operator:

return ++counter;

I would suggest to add a comment with that line. Why are you using prefix increment here? Does it matter? If another developer changes it, will it break something?

Note: you might leave counter start with the value 0 (which is the same as not specifying a value, since it gets zeroed), and use a prefix increment operator. That will also result in the first object getting the value 1.

Alternatively - and probably easier to understand - you can break it to two lines:

counter++;
return counter;

It should be clear that the above code returns the value after increment, as opposed to return counter++ which returns the value before the increment.


As I am doing it, I realized that "_Id" in contructor method is always "0" before taking the "IdAssignment()"'s value

C# guarantees that you will not get trash (the value that just happened to be there in the location of RAM associated with the variable). This means that if you did not initialize your fields, you get defaults (zeroed values). That is the 0 you see if you read _Id before _Id = IdAssignment() runs.


Shouldn't it be normally "1" as I come to taking second instance (C2)

No. _Id is not static. A new _Id is allocated for each new object of your class, and thus it has nothing to do with the value of _Id found in any object created beforehand. On the other hand, counter IS static, and thus it is only one field for all the objects (instead of allocating a new counter per object, a single one is shared).

OTHER TIPS

Re, question1, you are using the post increment operator when doing return counter++;. In other words, it'll read the value of counter, save that value as your return value, then increment counter. So on the first call, 1 is returned and counter is updated to 2.

Re question 2, if I understand the question correctly, every time a new instance of Computer is created, its fields are initialised to 0, null etc. So in this case, _Id will always be set to 0 when constructed, then is overwritten. What value may exist in other instances of Computer will not affect it.

Licensed under: CC-BY-SA with attribution
scroll top