.NET Internals Cookbook Part 7 — Word tearing, locking and others

This is the seventh part of the .NET Internals Cookbook series. For your convenience you can find other parts in the table of contents in Part 0 – Table of contents

45. Should we always avoid boxing?

Boxing is expensive, it wraps value types into reference instances so we lose some performance. However, take this code:

using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; public class Program { public static void Main() { var source = Enumerable.Range(0, 1000).ToArray(); while(true) { Foo result = UnsafeParallel(source, n => { Thread.Sleep(0); return new Foo { A = n, B = n, C = n, D = n, E = n }; }); if (result.A != result.B || result.A != result.C || result.A != result.D || result.A != result.E) { Console.WriteLine("Tearing detected!"); Console.WriteLine(result.A); Console.WriteLine(result.B); Console.WriteLine(result.C); Console.WriteLine(result.D); Console.WriteLine(result.E); break; } } } static T UnsafeParallel<T>(IEnumerable<int> source, Func<int, T> action) { T result = default(T); Parallel.ForEach(source, (i, state) => { result = action(i); state.Stop(); }); return result; } static T SafeParallel<T>(IEnumerable<int> source, Func<int, T> action) { object result = default(T); Parallel.ForEach(source, (i, state) => { result = action(i); state.Stop(); }); return (T)result; } } struct Foo { public int A { get; set; } public int B { get; set; } public int C { get; set; } public int D { get; set; } public int E { get; set; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 using System ; using System . Collections . Generic ; using System . Linq ; using System . Threading ; using System . Threading . Tasks ; public class Program { public static void Main ( ) { var source = Enumerable . Range ( 0 , 1000 ) . ToArray ( ) ; while ( true ) { Foo result = UnsafeParallel ( source , n = > { Thread . Sleep ( 0 ) ; return new Foo { A = n , B = n , C = n , D = n , E = n } ; } ) ; if ( result . A != result . B || result . A != result . C || result . A != result . D || result . A != result . E ) { Console . WriteLine ( "Tearing detected!" ) ; Console . WriteLine ( result . A ) ; Console . WriteLine ( result . B ) ; Console . WriteLine ( result . C ) ; Console . WriteLine ( result . D ) ; Console . WriteLine ( result . E ) ; break ; } } } static T UnsafeParallel < T > ( IEnumerable < int > source , Func < int , T > action ) { T result = default ( T ) ; Parallel . ForEach ( source , ( i , state ) = > { result = action ( i ) ; state . Stop ( ) ; } ) ; return result ; } static T SafeParallel < T > ( IEnumerable < int > source , Func < int , T > action ) { object result = default ( T ) ; Parallel . ForEach ( source , ( i , state ) = > { result = action ( i ) ; state . Stop ( ) ; } ) ; return ( T ) result ; } } struct Foo { public int A { get ; set ; } public int B { get ; set ; } public int C { get ; set ; } public int D { get ; set ; } public int E { get ; set ; } }

The only difference between UnsafeParallel and SafeParallel is that the former stores the result in a T variable, the latter stores just an object.

Now, what happens if you use value types? Since they can be bigger than a reference, they do not need to be stored atomically. So if two threads try to write to result at the same time we may get the write tearing. Run the code to see that it is happening indeed — we get mixed content.

However, if we use SafeParallel , the value type is boxed so it is stored atomically (because only reference needs to be stored). Thanks to that we never get broken data.

46. What happens if first delegate method throws an exception?

It stops executing other callbacks, as shown here:

using System; public class Program { delegate void Foo(); public static void Main() { Foo foo = () => Console.WriteLine("First"); foo += () => throw new Exception("Second"); foo += () => Console.WriteLine("Third"); try{ foo(); }catch(Exception e){ Console.WriteLine(e); } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 using System ; public class Program { delegate void Foo ( ) ; public static void Main ( ) { Foo foo = ( ) = > Console . WriteLine ( "First" ) ; foo += ( ) = > throw new Exception ( "Second" ) ; foo += ( ) = > Console . WriteLine ( "Third" ) ; try { foo ( ) ; } catch ( Exception e ) { Console . WriteLine ( e ) ; } } }

Output:

First System.Exception: Second at Program.<>c.<Main>b__1_1() in /home/runner/.code.tio:line 9 at Program.Main() in /home/runner/.code.tio:line 13 1 2 3 4 First System . Exception : Second at Program . <> c . < Main > b__1_1 ( ) in / home / runner / . code . tio : line 9 at Program . Main ( ) in / home / runner / . code . tio : line 13

47. Does foreach require interface? What is a WellKnownMember ?

No, as shown here:

using System; public class Program { public static void Main() { var bar = new Bar(); foreach (int item in bar) { Console.WriteLine(item); } } } class Foo { public int Current { get; private set; } private int step; public bool MoveNext() { if (step >= 5) return false; Current = step++; return true; } } class Bar { public Foo GetEnumerator() { return new Foo(); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 using System ; public class Program { public static void Main ( ) { var bar = new Bar ( ) ; foreach ( int item in bar ) { Console . WriteLine ( item ) ; } } } class Foo { public int Current { get ; private set ; } private int step ; public bool MoveNext ( ) { if ( step >= 5 ) return false ; Current = step ++ ; return true ; } } class Bar { public Foo GetEnumerator ( ) { return new Foo ( ) ; } }

foreach requires something with method GetEnumerator returning something with Current and bool MoveNext() . This is a duck typing. The same rule goes for await as shown here:

using System; using System.Runtime.CompilerServices; using System.Threading.Tasks; namespace AwaitOnInteger { class Program { static void Main(string[] args) { WaitForInt().Wait(); } static async Task WaitForInt() { Console.WriteLine($"Waiting starting at {DateTime.Now}"); await 2000; Console.WriteLine($"Waiting finished at {DateTime.Now}"); } } public static class AwaitableInt { public static TaskAwaiter GetAwaiter(this int miliseconds) { return Task.Delay(TimeSpan.FromMilliseconds(miliseconds)).GetAwaiter(); } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 using System ; using System . Runtime . CompilerServices ; using System . Threading . Tasks ; namespace AwaitOnInteger { class Program { static void Main ( string [ ] args ) { WaitForInt ( ) . Wait ( ) ; } static async Task WaitForInt ( ) { Console . WriteLine ( $ "Waiting starting at {DateTime.Now}" ) ; await 2000 ; Console . WriteLine ( $ "Waiting finished at {DateTime.Now}" ) ; } } public static class AwaitableInt { public static TaskAwaiter GetAwaiter ( this int miliseconds ) { return Task . Delay ( TimeSpan . FromMilliseconds ( miliseconds ) ) . GetAwaiter ( ) ; } } }

Actually, there are a lot of WellKnownMember which are used by the compiler.

48. How does LINQ query syntax work? How is it compiled?

They are compiled to normal Where , Select , Join and other methods. Try decompiling the following code:

using System; using System.Linq; namespace Program { public class Program { public static void Main(string[] args) { var source = Enumerable.Range(0, 100); var filtered = from i in source where i % 3 == 0 select i / 2; } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 using System ; using System . Linq ; namespace Program { public class Program { public static void Main ( string [ ] args ) { var source = Enumerable . Range ( 0 , 100 ) ; var filtered = from i in source where i % 3 == 0 select i / 2 ; } } }

You should get something similar to:

using System; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; namespace Program { public class Program { [CompilerGenerated] [Serializable] private sealed class <>c { public static readonly Program.<>c <>9 = new Program.<>c(); public static Func<int, bool> <>9__0_0; public static Func<int, int> <>9__0_1; internal bool <Main>b__0_0(int i) { return i % 3 == 0; } internal int <Main>b__0_1(int i) { return i / 2; } } public static void Main(string[] args) { IEnumerable<int> enumerable = Enumerable.Range(0, 100); IEnumerable<int> arg_2A_0 = enumerable; Func<int, bool> arg_2A_1; if ((arg_2A_1 = Program.<>c.<>9__0_0) == null) { arg_2A_1 = (Program.<>c.<>9__0_0 = new Func<int, bool>(Program.<>c.<>9.<Main>b__0_0)); } IEnumerable<int> arg_4E_0 = arg_2A_0.Where(arg_2A_1); Func<int, int> arg_4E_1; if ((arg_4E_1 = Program.<>c.<>9__0_1) == null) { arg_4E_1 = (Program.<>c.<>9__0_1 = new Func<int, int>(Program.<>c.<>9.<Main>b__0_1)); } IEnumerable<int> enumerable2 = arg_4E_0.Select(arg_4E_1); } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 using System ; using System . Collections . Generic ; using System . Linq ; using System . Runtime . CompilerServices ; namespace Program { public class Program { [ CompilerGenerated ] [ Serializable ] private sealed class <> c { public static readonly Program . <> c <> 9 = new Program . <> c ( ) ; public static Func < int , bool > <> 9__0_0 ; public static Func < int , int > <> 9__0_1 ; internal bool < Main > b__0_0 ( int i ) { return i % 3 == 0 ; } internal int < Main > b__0_1 ( int i ) { return i / 2 ; } } public static void Main ( string [ ] args ) { IEnumerable < int > enumerable = Enumerable . Range ( 0 , 100 ) ; IEnumerable < int > arg_2A_0 = enumerable ; Func < int , bool > arg_2A_1 ; if ( ( arg_2A_1 = Program . <> c . <> 9__0_0 ) == null ) { arg_2A_1 = ( Program . <> c . <> 9__0_0 = new Func < int , bool > ( Program . <> c . <> 9. < Main > b__0_0 ) ) ; } IEnumerable < int > arg_4E_0 = arg_2A_0 . Where ( arg_2A_1 ) ; Func < int , int > arg_4E_1 ; if ( ( arg_4E_1 = Program . <> c . <> 9__0_1 ) == null ) { arg_4E_1 = ( Program . <> c . <> 9__0_1 = new Func < int , int > ( Program . <> c . <> 9. < Main > b__0_1 ) ) ; } IEnumerable < int > enumerable2 = arg_4E_0 . Select ( arg_4E_1 ) ; } } }

49. What is the difference between Select in IEnumerable and IQueryable ?

This is Enumerable.Select :

public static System.Collections.Generic.IEnumerable<TResult> Select<TSource,TResult> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,int,TResult> selector); 1 public static System . Collections . Generic . IEnumerable < TResult > Select < TSource , TResult > ( this System . Collections . Generic . IEnumerable < TSource > source , Func < TSource , int , TResult > selector ) ;

This is Queryable.Select :

public static System.Linq.IQueryable<TResult> Select<TSource,TResult> (this System.Linq.IQueryable<TSource> source, System.Linq.Expressions.Expression<Func<TSource,int,TResult>> selector); 1 public static System . Linq . IQueryable < TResult > Select < TSource , TResult > ( this System . Linq . IQueryable < TSource > source , System . Linq . Expressions . Expression < Func < TSource , int , TResult >> selector ) ;

Apart from different interfaces, they accept lambda in different way. Enumerable gets normal lambda and executes it directly. Queryable takes expression which is just a lambda syntax tree. It is not executed at all, it is later translated to SQL query.

50. How to block access to private members via reflection?

You can use DisablePrivateReflectionAttribute on the assembly level.

You can also use ReflectionPermission.

51. Can you lock a value type?

No and yes (but still no). If you try this:

using System; namespace Program { public class Program { public static void Main(string[] args) { int i = 5; lock(i){ } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 using System ; namespace Program { public class Program { public static void Main ( string [ ] args ) { int i = 5 ; lock ( i ) { } } } }

you will get:

Compilation error (line 10, col 9): 'int' is not a reference type as required by the lock statement 1 Compilation error ( line 10 , col 9 ) : 'int' is not a reference type as required by the lock statement

So we cannot just lock it. But we know that lock uses monitors, so let’s try this:

using System; using System.Threading; namespace Program { public class Program { public static void Main(string[] args) { int i = 5; bool wasTaken = false; try{ Monitor.Enter(i, ref wasTaken); }finally{ if(wasTaken){ Monitor.Exit(i); } } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 using System ; using System . Threading ; namespace Program { public class Program { public static void Main ( string [ ] args ) { int i = 5 ; bool wasTaken = false ; try { Monitor . Enter ( i , ref wasTaken ) ; } finally { if ( wasTaken ) { Monitor . Exit ( i ) ; } } } } }

It compiles but crashes, why? This is because we use boxing so we are not locking on the value but on the boxed object. We could store the reference as in here:

using System; using System.Threading; namespace Program { public class Program { public static void Main(string[] args) { int i = 5; object reference = i; bool wasTaken = false; try { Monitor.Enter(reference, ref wasTaken); } finally { if (wasTaken) { Monitor.Exit(reference); } } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 using System ; using System . Threading ; namespace Program { public class Program { public static void Main ( string [ ] args ) { int i = 5 ; object reference = i ; bool wasTaken = false ; try { Monitor . Enter ( reference , ref wasTaken ) ; } finally { if ( wasTaken ) { Monitor . Exit ( reference ) ; } } } } }

This works but now we risk locking on different boxed instance. So generally — don’t do that.