-2

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

3
  • Question1 isn't clear. Where exactly are the breakpoints, in what order are they hit, and what are the values there? And what is the behavior you expect to see? Question2 just seems to be a misunderstanding of how instance variables work. Either way, these are two very different questions, and you shouldn't put them in the same question. (The second one is almost guaranteed to be a duplicate.) Aug 12, 2019 at 13:32
  • no comment on this Aug 12, 2019 at 15:37
  • Q2: No - each instance is independent (metaphorically, it's like a completely new object is being produced in a factory); and all fields are first initialized to default values on construction (0 for integers). This is the reason why you need the static counter field - because it doesn't belong to any specific instance (but to the class itself). It's like a separate scratch pad where you are saving the last used ID. When you create a new instance, the the _Id always starts out as 0, then in the constructor, you look up where the counter is currently at, and assign the value based on that. Aug 12, 2019 at 15:51

2 Answers 2

0

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).

1
  • Thanks a lot for your time and help. I perfectly understand why it's not incrementing on _Id. I did mention that I am a learner and I didn't know the true meaning of counter++ other than incrementing the value by 1. So, your explanation makes sense right now. And for the second question, I understand that without static values, the class' variables/fields get only their default values when you take seperate instances of class because you are just taking a copy of them at default. Again, thank you for your time and help, Melih. Aug 12, 2019 at 15:57
0

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.

Not the answer you're looking for? Browse other questions tagged or ask your own question.