How the immutability of C# delegates (and strings) is implemented at the bottom?

  • Thread starter Thread starter LiveLikeAChild
  • Start date Start date
L

LiveLikeAChild

Guest
In C#, for invoking a delegate in a thread-safe style, we can use the following code:

```
public static void TestInvokeDelegate1()
{
CustomClass cc1 = new CustomClass("cc1");
Action action = cc1.WriteName;

Action action2 = action;
if(action2 != null)
{
action2();
}
}
```

Or, in C# 6.0 or later, we can also use:

```
public static void TestInvokeDelegate2()
{
CustomClass cc1 = new CustomClass("cc1");
Action action = cc1.WriteName;

action?.Invoke();
}
```

As we know, these codes use the immutability of delegates to achieve thread safety. But how the immutability is done inside the .net compiler or runtime? I use the Ildasm tool to get the IL codes of these two methods:

```
.method public hidebysig static void TestInvokeDelegate1() cil managed
{
// 32 (0x20)
.maxstack 2
.locals init (class [System.Runtime]System.Action V_0)
IL_0000: ldstr "cc1"
IL_0005: newobj instance void ess_cs.CustomClass::.ctor(string)
IL_000a: ldftn instance void ess_cs.CustomClass::WriteName()
IL_0010: newobj instance void [System.Runtime]System.Action::.ctor(object,
native int)
IL_0015: stloc.0
IL_0016: ldloc.0
IL_0017: brfalse.s IL_001f
IL_0019: ldloc.0
IL_001a: callvirt instance void [System.Runtime]System.Action::Invoke()
IL_001f: ret
} // end of method Program::TestInvokeDelegate1
```
and,

```
.method public hidebysig static void TestInvokeDelegate2() cil managed
{
// 32 (0x20)
.maxstack 8
IL_0000: ldstr "cc1"
IL_0005: newobj instance void ess_cs.CustomClass::.ctor(string)
IL_000a: ldftn instance void ess_cs.CustomClass::WriteName()
IL_0010: newobj instance void [System.Runtime]System.Action::.ctor(object,
native int)
IL_0015: dup
IL_0016: brtrue.s IL_001a
IL_0018: pop
IL_0019: ret
IL_001a: callvirt instance void [System.Runtime]System.Action::Invoke()
IL_001f: ret
} // end of method Program::TestInvokeDelegate2
```

I am not proficient in IL, but in these IL codes, what I seen are only copying reference to an object. By simply copying reference, the two variables are pointing to the same object, where is the immutability? There are no code to copy object data, how it is implemented? (Also the immutability of strings)


------------------------------------------------------------------

Additional text: codes writen by me for testing the immutability of strings and delegates:

**(NOTE: I know every thing in C# level of the following codes, it is writen by me to testing the immutability of strings or delegates. It seems that the object is copyed when the variable pointing to it is assigned to another variable. But in the IL codes, I cannot find the object-copy code. What I want to know is the internal implementadtion of the immutability, in compiler or runtime (clr) level. What happened at behind?)**

```
public static void TestStringImmutable()
{
string s1 = "abc";
string s2 = s1;
s1 = "ab";
Console.WriteLine(s1); //"ab"
Console.WriteLine(s2); //"abc"

s1 = "abcde";
Console.WriteLine(s1); //"abcde"
Console.WriteLine(s2); //"abc"
}
```

and,

```
public static void TestDelegateImmutable()
{
CustomClass cc1 = new CustomClass("cc1");
CustomClass cc2 = new CustomClass("cc2");

Action action = cc1.WriteName;
action += cc2.WriteName;
Action action2 = action;
action -= cc2.WriteName;

action(); //Output: "cc1"
action2(); //Output: "cc1" and "cc2"

action -= cc1.WriteName;
Console.WriteLine(action == null); //true
Console.WriteLine(action2 == null); //false
Console.WriteLine(action2.GetInvocationList().Length); //2
}
```

----------------------------------------------------------------------

The **CustomClass** class:

```
class CustomClass
{
private string m_name = null;

public CustomClass(string name)
{
m_name = name;
}

public void WriteName()
{
Console.WriteLine(m_name);
}
}
```

Continue reading...
 
Back
Top