To give another way of looking at this that has nothing to do with threads: the compiler behaves this way because that's the way the language is specified.
From the ECMA C# 5 specification section 10.4.4.16:
Try-catch-finally statements
Definite assignment analysis for a try-catch-finally
statement of the form:
try try-block
catch ( … ) catch-block-1
…
catch ( … ) catch-block-n
finally finally-block
is done as if the statement were a try-finally statement enclosing a try-catch statement:
try {
try try-block
catch ( … ) catch-block-1
…
catch ( … ) catch-block-n
}
finally finally-block
So how does a try-finally statement work in terms of definite assignment? That's in section 10.4.4.16:
For a try
statement stmt of the form:
try try-block finally finally-block
- ...
- The definite assignment state of v at the beginning of finally-block is the same as the definite assignment state of v at the beginning of stmt.
So what does that mean in your case? At the start of the statement, your variable str
is not definitely assigned... so by those rules, it's also not definitely assigned at the start of the finally
block.
Now, why was the language designed that way? That's a slightly different question. I don't think that has anything to do with threads. The language generally assumes that anything can throw an exception. The only way a variable becomes definitely assigned is for it to be assigned a value and that assignment complete without throwing an exception. Any code path that could occur even if an exception occurs before assignment cannot be considered to definitely assign the variable.
As a simple example, imagine we changed your code to:
string str;
try
{
str = MethodThatThrowsAnException();
}
catch (Exception)
{
str = MethodThatThrowsAnException();
}
finally
{
Console.WriteLine(str);
}
At that point, it doesn't seem so odd that str
is not definitely assigned. It's only because it's assigning a string literal that it looks like it can't possibly fail. But I could imagine even assigning a string literal failing, if it's the first time that string constant has been seen, and it needs to allocate a String
object... that allocation could fail. Then there are all the other ways that exceptions can be thrown, including threads being aborted.
All of this means:
- The first statement in the
try
block can throw an exception
- The first statement in the
catch
block can throw an exception
In that situation - however that occurs, and whether it's got anything to do with threading or not (it could be an allocation failure, for example) - you won't have executed any assignment to str
, so it has no defined value to read.