3

I'm working on doing some refactoring of functions in an existing ASP.NET MVC application, and came across the following small recursive function within a controller. I'm a little new still to C# & .NET, so please bear with me if I get some things wrong.

private int _bl;
[Session]
public void TotalMaterialSubCategories(IEnumerable<Category> materialMasterCats, int i)
{
    foreach (var materialMasterCat in materialMasterCats)
    {
        _bl = _bl + 1;
        materialMasterCat.Level = i;
        if (materialMasterCat.ChildCategories.Count != 0)
        {
            TotalMaterialSubCategories(materialMasterCat.ChildCategories.ToList(), i + 1);
            if (materialMasterCat.Parent == 0)
            {
                materialMasterCat.SortOrder = _bl;
                _bl = 0;
            }
        }
    }
}

The thing about it that concerned me is this private int _bl statement. Within this class, the only references to this variable are associated with this function.

I thought the line _b1 = _b1 + 1 might not be reliable because it's not manually initialized. Looking into it though, I believe that since it's an int, it cannot be null or left 'uninitialized', so it's getting a default value of 0; corroborated by the MS Docs. The way the recursion looks like it bubbles up makes me think it'll be set back to 0 at the end of this function call as well. Finally, I'm pretty sure each independent web request gets a separate instance of this controller, so it seems like the way this is written, it should function as expected.

However, I just sort of wondered why this would be written like this. Is there a reason that this isn't just a local variable to the function, initialized with 0? Can you rely on local private variables across functions in controllers? Also, are any of my assumptions / determinations incorrect?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Lovethenakedgun
  • 731
  • 6
  • 22
  • 2
    Your assumptions are correct. The value of `_b1` will be initialized to 0 in each request. As to why they did it that, only the person who authored could tell you for sure –  Aug 09 '18 at 06:51

2 Answers2

2

I believe that since it's an int, it cannot be null or left 'uninitialized', so it's getting a default value of 0; corroborated by the MS Docs

Try putting the private int _bl; inside of a function as int _bl; and you will see that you get a compile error because you can't perform a _bl = _bl + 1; operation on uninitialized value. So, it doesn't get automatically initialized in scope of a function, but it does get automatically initialized when it's a property of a class instance.

You can read more on when a value gets assigned and when it doesn't here: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/variables This particular case falls to:

An instance variable of a class comes into existence when a new instance of that class is created, and ceases to exist when there are no references to that instance and the instance's destructor (if any) has executed. The initial value of an instance variable of a class is the default value (Default values) of the variable's type. For the purpose of definite assignment checking, an instance variable of a class is considered initially assigned.

Erndob
  • 2,512
  • 20
  • 32
  • Ah, yep, thanks for the clarification on that. Do you know of any reason why it would've been written with the private object variable, rather than declaring a variable within the function as `int _bl = 0;`? Is it somehow more usable or efficient like this? – Lovethenakedgun Aug 09 '18 at 07:05
  • Erik Philips has a perfect answer on that. – Erndob Aug 09 '18 at 07:24
2

The thing about it that concerned me is this private int _bl statement. Within this class, the only references to this variable are associated with this function.

Obviously we can't see all the code, but if I were to believe you that this Field(not variable) is only referenced by this function then I would surmise that either it's left over when other methods may have referenced it and now those methods no longer exist, used it OR it used by a method to maintain state beyond the execution of any single method (event or property).

The way the recursion looks like it bubbles up makes me think it'll be set back to 0 at the end of this function call as well.

It's set to zero before the constructor is called.

Not necessarily. It's only set back to zero after the method ends if (materialMasterCat.Parent == 0) for each instantiation of this class.

Because controllers aren't static classes, each class create has it's own private version of _bl that can only (normally) be access by the class itself (private access modifer).

However, I just sort of wondered why this would be written like this. Is there a reason that this isn't just a local variable to the function, initialized with 0?

Because then when this code ran, all of them would have a value of 1:

materialMasterCat.SortOrder = _bl;

But what's happening is that each time the function is called, it's being incremented because it's exists in the class's scope, not the functions scope.

For Example

Can you rely on local private variables across functions in MVC Controllers?

Private variables are always available until a class is disposed (generally), this time is referred to as the Lifetime of an object.

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
  • Ah right, it somehow slipped past me that it's using that field to hold state between the recursive calls; probably because it's passing `i` but not `_bl`-- Thanks for that. Incidentally, is there any way to know when a controller instance will be disposed of, or if a user can expect to be interacting with the same controller instance between HTTP requests? – Lovethenakedgun Aug 09 '18 at 07:21
  • 2
    Controller instance is created for each http request. They won't be reused. It will be disposed once you send the response back to the client. – Erndob Aug 09 '18 at 07:23