Don't forget that C# constructor overloads and method overloads work in opposite ways
It's 9pm and I'm using the quiet time in the office to write some unit tests for our new CMS product. This process just uncovered an interesting bug:
1 public class SecurityManager {
2
3 public SecurityManager () {
4
5 if(user == null) {
6 this._user = User.CurrentUser;
7 }
8 9 InitialiseData();
10
11 }
12
13 public SecurityManager(User user) : this() {
14
15 this._user = user;
16
17 }
18
19 private User _user;
20
21 }
The static method User.CurrentUser returns the currently logged in user (using HttpContext.Current). This code was working fine in the web application but the unit tests were failing (throwing a NullReferenceException). The stack trace showed that the exception was being thrown from Line 6. But NUnit was calling the second constructor with a non-null User object. Line 6 shouldn't even be hit. I was confused until I remembered the order of execution for C# constructors.
public SecurityManager () {
Console.WriteLine("This will be executed first");
}
public SecurityManager(User user) : this() {
Console.WriteLine("This will be executed second");
}
The fix was simple:
public class SecurityManager {
public SecurityManager () : this(null) {
}
public SecurityManager(User user) {
this._user = user;
if(user == null) {
this._user = User.CurrentUser;
}
InitialiseData();
}
private User _user;
}
I got confused because I expected the constructor I called to be run first, just as method overloads work. In fact, constructor overloads work in the opposite way to method overloads:
public void CreateSecurityManager() {
Console.WriteLine("This will be executed second");
}
public void CreateSecurityManager(User user) {
Console.WriteLine("This will be executed first");
this._user = user;
CreateSecurityManager();
}
What a stupid mistake! I've just checked the last couple of classes I've written and they were correct - I guess the coffee was wearing off when I wrote this class.
I like blogging about embarressingly obvious mistakes like this because it means I'll never make the mistake again. :-)