If the code is changed to:
lock ("1" + "2")
{
Console.WriteLine("outer lock");
Task.Factory.StartNew(() =>
{
lock ("12")
{//launched afetr 10 second
Console.WriteLine("inner lock");
}
});
Thread.Sleep(10000);
}
then "inner lock" will be printed 10 seconds after "outter lock".
Which means "1" + "2" is literally equal to "12".
However, if using .NET Reflector to open the IL code for:
lock ("1" + "2")
{
Console.WriteLine("outer lock");
Task.Factory.StartNew(() =>
{
var a = "1";
lock (a + "2")
{//launched afetr 10 second
Console.WriteLine("inner lock");
}
});
Thread.Sleep(10000);
}
The IL will show following code for the outer lock
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 3
.locals init (
[0] bool flag,
[1] string str,
[2] bool flag2)
L_0000: nop
L_0001: ldc.i4.0
L_0002: stloc.0
L_0003: ldstr "12"
L_0008: dup
L_0009: stloc.1
L_000a: ldloca.s flag
L_000c: call void [mscorlib]System.Threading.Monitor::Enter(object, bool&)
L_0011: nop
L_0012: nop
L_0013: ldstr "outer lock"
L_0018: call void [mscorlib]System.Console::WriteLine(string)
The IL code:
L_0003: ldstr "12"
L_0008: dup
L_0009: stloc.1
L_000a: ldloca.s flag
eventually save "12" into local varaible
The IL code for "inner lock" is
.method private hidebysig static void <Main>b__3() cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
.maxstack 2
.locals init (
[0] string str,
[1] bool flag,
[2] string str2,
[3] bool flag2)
L_0000: nop
L_0001: ldstr "1"
L_0006: stloc.0
L_0007: ldc.i4.0
L_0008: stloc.1
L_0009: ldloc.0
L_000a: ldstr "2"
L_000f: call string [mscorlib]System.String::Concat(string, string)
L_0014: dup
L_0015: stloc.2
L_0016: ldloca.s flag
L_0018: call void [mscorlib]System.Threading.Monitor::Enter(object, bool&)
The IL code:
L_0001: ldstr "1"
L_0006: stloc.0
L_0007: ldc.i4.0
L_0008: stloc.1
L_0009: ldloc.0
L_000a: ldstr "2"
L_000f: call string [mscorlib]System.String::Concat(string, string)
store "1" in a local variable, and store "2" in another local variable. Then call String.Concat.
If you try another code: (in another console program)
var c = "1" + "2";
var d = c + "2";
Console.WriteLine(string.IsInterned(d));
var e = "12";
Console.WriteLine(string.IsInterned(e));
You will find the first string.IsInterned(d) return nothing, but second string.IsInterned(e) will print "12" in console.
Because c + "2" is not literally equal to "1" + "2", but "12" is literally equal to "12".
Which means even c + "2" will return you "12", but internally they are different expression. Which means your original second "lock (a + "2")" is trying to lock on a different expression, and that's why your second code block will be executed immediately.