This:
CheckPasswords(out notUsed, out notUsed);
does not pass the contents of notUsed to the method (as would happen in a method that didn't use out parameters), it passes a reference to notUsed to the method. The same reference twice, in fact. As you say, at this point notUsed does not contain a reference itself yet, but that doesn't matter -- we are not doing anything with the contents, in fact, we don't care since we're passing it as out. Then this:
user1 = "A";
does something special because user1 is not a string parameter -- it's an out string parameter. Rather than assign a value to some local user1, it assigns a value to what user1 is pointing to -- in this case, notUsed. At this point, notUsed holds a reference to "A". And then this:
user2 = "B";
does the same thing, but through the other parameter -- it assigns a reference to "B" to notUsed. And then these two lines:
Console.WriteLine("user1: " + user1);
Console.WriteLine("user2: " + user2);
retrieve not the contents of any local variable, but the value in notUsed, since both user1 and user2 point to it. So, of course, you'll get "B" twice.
It is no more shocking than this code:
class User {
public string Name { get; set; }
}
void NotMagic(User user1, User user2) {
user1.Name = "A";
user2.Name = "B";
Console.WriteLine("user1.Name = " + user1.Name);
Console.WriteLine("user2.Name = " + user2.Name);
}
void Main() {
User user = new User();
NotMagic(user, user);
}
You probably wouldn't be surprised if this printed B twice. That there are two different parameters in NotMagic doesn't mean they can't both point to the same thing. Same with out and ref parameters, except that the syntax will hide the extra indirection for you.
notUsedhaving two values?notUsedto be and why?outvariable, those are never instanced before you're calling the method. Nevertheless, it's the same variable referenced twice, not two local variables that are "copied out" at the end of the method.user1 = "A". Sinceuser1points tonotUsed, the reference to"A"ends up innotUsed. (And then, of course, it is overwritten by the second statement, sinceuser2also points tonotUsed.) The storage needed fornotUsedalready exists, even if its contents does not at method entry (or more accurately, the contents are indeterminate/inaccessible).