This is the sixth 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
Table of Contents
36. What is a shim?
.NET applications are started directly, the same way as native applications are. The entry point of the binary points to mscoree.dll (execution engine) which then checks the metadata of the file, loads correct .NET runtime and passes the execution using _CorExeMain function. The part of mscoree is sometimes called “loading shim”. See this for more details.
This means that in native code you can load .NET manually and execute some managed code. See this to get some more code.
37. How many bytes does an empty structure have?
“Zero” makes perfect sense as the structure is empty so it should occupy no space. However, this would make pointer arithmetic a little weird — you could allocate two structures, one next to another and they would all be pointing to the same address. Because of that the empty structure takes one byte. See this code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
using System; public class Program { public static void Main() { Console.WriteLine(System.Runtime.InteropServices.Marshal.SizeOf(typeof(Foo))); Console.WriteLine(System.Runtime.InteropServices.Marshal.SizeOf(typeof(Bar))); } } struct Foo{ } struct Bar{ int x; } |
Output:
1 2 |
1 4 |
You could also ask how many bytes would empty class have — it is 3 pointers (so 12 bytes on x86 or 24 bytes on x64). This includes space for sync block, space for Method Table pointer, and some more bytes so the GC can work properly.
38. What is a sync block?
Information that the object is locked must be stored somewhere. Whenever you have a reference to an object, it does not point to the object beginning. Actually, before the place pointed by the reference there is a header called “sync block”. You can verify it with the following code and WinDBG:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
using System; namespace ConsoleApp { class Program { public static void Main() { var foo = new Foo(); Console.WriteLine("Foo created"); Console.ReadLine(); lock (foo) { Console.WriteLine("Foo locked"); Console.ReadLine(); } } } class Foo { } } |
Attach WinDBG after seeing “Foo created” but before typing anything. You should get this:
1 |
0:006> .loadby sos clr |
1 2 3 4 5 6 |
0:006> ~0s eax=00000000 ebx=00000090 ecx=00000000 edx=00000000 esi=010ff3b4 edi=00000000 eip=7782265c esp=010ff29c ebp=010ff2fc iopl=0 nv up ei pl nz na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206 ntdll!NtReadFile+0xc: 7782265c c22400 ret 24h |
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 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
0:000> !clrstack -a -i Loaded C:\tmp\mscordbi.dll\5B88589711f000\mscordbi.dll Loaded C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscordacwks.dll Dumping managed stack and managed variables using ICorDebug. ============================================================================= Child SP IP Call Site 010ff29c 7782265c [NativeStackFrame] 010ff318 72a631df 010ff31c (null) [Managed to Unmanaged transition: 010ff31c] 010ff380 731a0163 [DEFAULT] I4 System.IO.__ConsoleStream.ReadFileNative(Class Microsoft.Win32.SafeHandles.SafeFileHandle,SZArray UI1,I4,I4,Boolean,Boolean,ByRef I4) (C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll) PARAMETERS: + (Error 0x80131304 retrieving parameter 'hFile') + (Error 0x80131304 retrieving parameter 'bytes') + (Error 0x80131304 retrieving parameter 'offset') + (Error 0x80131304 retrieving parameter 'count') + (Error 0x80131304 retrieving parameter 'useFileAPIs') + (Error 0x80131304 retrieving parameter 'isPipe') + (Error 0x80131304 retrieving parameter 'bytesRead') LOCALS: + (Error 0x80004005 retrieving local variable 'readSuccess') + (Error 0x80004005 retrieving local variable 'errorCode') + byte& p = 0 + (Error 0x80004005 retrieving local variable 'local_3') + (Error 0x80004005 retrieving local variable 'p') + (Error 0x80004005 retrieving local variable 'charsRead') 010ff3b4 731a0072 [DEFAULT] [hasThis] I4 System.IO.__ConsoleStream.Read(SZArray UI1,I4,I4) (C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll) PARAMETERS: + (Error 0x80131304 retrieving parameter 'this') + (Error 0x80131304 retrieving parameter 'buffer') + (Error 0x80131304 retrieving parameter 'offset') + (Error 0x80131304 retrieving parameter 'count') LOCALS: + (Error 0x80004005 retrieving local variable 'bytesRead') + (Error 0x80004005 retrieving local variable 'errCode') 010ff3d4 72994dd7 [DEFAULT] [hasThis] I4 System.IO.StreamReader.ReadBuffer() (C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll) PARAMETERS: + System.IO.StreamReader this @ 0x3284174 LOCALS: + (Error 0x80004005 retrieving local variable 'len') + (Error 0x80004005 retrieving local variable 'local_1') 010ff3e4 72a14b18 [DEFAULT] [hasThis] String System.IO.StreamReader.ReadLine() (C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll) PARAMETERS: + System.IO.StreamReader this @ 0x3284174 LOCALS: + (Error 0x80004005 retrieving local variable 'sb') + (Error 0x80004005 retrieving local variable 'i') + (Error 0x80004005 retrieving local variable 'ch') + (Error 0x80004005 retrieving local variable 's') 010ff400 732e1c61 [DEFAULT] [hasThis] String System.IO.TextReader+SyncTextReader.ReadLine() (C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll) PARAMETERS: + System.IO.TextReader+SyncTextReader this @ 0x32844f4 LOCALS: (none) 010ff410 73148310 [DEFAULT] String System.Console.ReadLine() (C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll) PARAMETERS: (none) LOCALS: (none) 010ff418 013304a1 [DEFAULT] Void ConsoleApp.Program.Main() (C:\Users\adafurma\source\repos\ConsoleApp3\ConsoleApp3\bin\Debug\ConsoleApp3.exe) PARAMETERS: (none) LOCALS: + ConsoleApp.Foo foo @ 0x32823fc + (Error 0x80004005 retrieving local variable 'local_1') + (Error 0x80004005 retrieving local variable 'local_2') 010ff450 73a9ebb6 [NativeStackFrame] Stack walk complete. ============================================================================= |
So we can see there is an object. Let’s examine it:
1 2 3 4 5 6 7 8 |
0:000> !do 0x32823fc Name: ConsoleApp.Foo MethodTable: 01274da4 EEClass: 012716f8 Size: 12(0xc) bytes File: C:\Users\adafurma\source\repos\ConsoleApp3\ConsoleApp3\bin\Debug\ConsoleApp3.exe Fields: None |
And now let’s see raw bytes:
1 2 3 4 5 6 7 8 9 |
0:000> dd 0x32823fc-4 032823f8 00000000 01274da4 00000000 00000000 03282408 72aac29c 00000000 00000000 00000000 03282418 00000000 00000000 00000000 72aa14c8 03282428 00000000 03282454 03282464 000004b0 03282438 00000100 00000000 00000000 72a9eb40 03282448 00000001 0000fffd 00000000 72aa1768 03282458 00000000 03282444 00000000 72aa17b8 03282468 00000000 03282444 00000000 72a9eee0 |
Notice that I subtracted 4 bytes (this is 32-bit application). You can see Method Table pointer and 4 zeros just before that.
Let’s now continue our application and take a lock.
1 |
0:000> g |
Type anything, hit enter, see “Foo locked”, break again and repeat last action:
1 2 3 4 5 6 7 8 9 |
0:008> dd 0x32823fc-4 032823f8 00000001 01274da4 00000000 00000000 03282408 72aac29c 00000000 00000000 00000000 03282418 00000000 00000000 00000000 72aa14c8 03282428 00000000 03282454 03282464 000004b0 03282438 00000100 00000000 00000000 72a9eb40 03282448 00000001 0000fffd 00000000 72aa1768 03282458 00000000 03282444 00000000 72aa17b8 03282468 00000000 03282444 00000000 72a9eee0 |
You can see that now there is value one before MT pointer. This is called “thin lock” which embeds locking information as a bit pattern.
Sync block is also used for caching hash code, COM interop and other things. Because there are only 4 bytes and we cannot put everything there, at some point it will get inflated so the sync block will be a pointer to the sync blocks table. You can read more here.
39. How many app domains are there by default?
3, as shown by WinDBG:
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 |
0:008> !dumpdomain -------------------------------------- System Domain: 7411d5a8 LowFrequencyHeap: 7411d8cc HighFrequencyHeap: 7411d918 StubHeap: 7411d964 Stage: OPEN Name: None -------------------------------------- Shared Domain: 7411d258 LowFrequencyHeap: 7411d8cc HighFrequencyHeap: 7411d918 StubHeap: 7411d964 Stage: OPEN Name: None Assembly: 01391f10 [C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll] ClassLoader: 01392df0 Module Name 725f1000 C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll -------------------------------------- Domain 1: 01365180 LowFrequencyHeap: 013655ec HighFrequencyHeap: 01365638 StubHeap: 01365684 Stage: OPEN SecurityDescriptor: 013667c8 Name: ConsoleApp3.exe Assembly: 01391f10 [C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll] ClassLoader: 01392df0 SecurityDescriptor: 01391dc0 Module Name 725f1000 C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll Assembly: 0139e6b0 [C:\Users\adafurma\source\repos\ConsoleApp3\ConsoleApp3\bin\Debug\ConsoleApp3.exe] ClassLoader: 01391a50 SecurityDescriptor: 0139e628 Module Name 01274024 C:\Users\adafurma\source\repos\ConsoleApp3\ConsoleApp3\bin\Debug\ConsoleApp3.exe |
These are:
- System app domain — loads mscorlib, creates
OutOfMemoryException
,StackoverflowException
andExecutionEngineException
(so they can always be thrown, even if there is not enough memory) and manages string interning - Shared app domain — contains mscorlib, types in
System
namespace and some code - Default — contains user code and resources
40. Does a value type have a method table?
Of course it does, somehow you need to be able to call virtual methods and box objects. See this code:
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 |
using System; namespace ConsoleApp { class Program { public static void Main() { object foo = new Foo(); Bar(foo); } static void Bar(object foo) { Console.WriteLine(foo.ToString()); Console.ReadLine(); } } struct Foo { public override string ToString() { return "Some string"; } } } |
Using WinDBG:
1 2 3 4 5 6 |
0:006> ~0s eax=00000000 ebx=00000090 ecx=00000000 edx=00000000 esi=0095eec4 edi=00000000 eip=7782265c esp=0095edac ebp=0095ee0c iopl=0 nv up ei pl nz na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206 ntdll!NtReadFile+0xc: 7782265c c22400 ret 24h |
1 |
0:000> .loadby sos clr |
1 2 3 4 5 6 |
0:000> !name2ee * Program Module: 725f1000 Assembly: mscorlib.dll -------------------------------------- Module: 00c94024 Assembly: ConsoleApp3.exe |
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 |
0:000> !dumpmodule -mt 00c94024 Name: C:\Users\adafurma\source\repos\ConsoleApp3\ConsoleApp3\bin\Debug\ConsoleApp3.exe Attributes: PEFile SupportsUpdateableMethods Assembly: 00b9d508 LoaderHeap: 00000000 TypeDefToMethodTableMap: 00c90038 TypeRefToMethodTableMap: 00c90048 MethodDefToDescMap: 00c90094 FieldDefToDescMap: 00c900a8 MemberRefToDescMap: 00000000 FileReferencesMap: 00c900b0 AssemblyReferencesMap: 00c900b4 MetaData start address: 005c20ac (1632 bytes) Types defined in this module MT TypeDef Name ------------------------------------------------------------------------------ 00c94d54 0x02000002 ConsoleApp.Program 00c94dbc 0x02000003 ConsoleApp.Foo Types referenced in this module MT TypeRef Name ------------------------------------------------------------------------------ 72a9eee0 0x02000010 System.Object 72aa0234 0x02000011 System.ValueType 72aac514 0x02000012 System.Console |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
0:000> !dumpmt -md 00c94dbc EEClass: 00c916f8 Module: 00c94024 Name: ConsoleApp.Foo mdToken: 02000003 File: C:\Users\adafurma\source\repos\ConsoleApp3\ConsoleApp3\bin\Debug\ConsoleApp3.exe BaseSize: 0xc ComponentSize: 0x0 Slots in VTable: 5 Number of IFaces in IFaceMap: 0 -------------------------------------- MethodDesc Table Entry MethodDe JIT Name 00d20058 00c94da8 NONE ConsoleApp.Foo.ToString() 72989dd0 725f85bc PreJIT System.ValueType.Equals(System.Object) 7290c578 725f85e4 NONE System.ValueType.GetHashCode() 729ebf8c 725f80b0 PreJIT System.Object.Finalize() 00d20508 00c94db0 JIT ConsoleApp.Foo.ToString() |
However, WinDBG is clever. See this:
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 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
0:000> !clrstack -a -i Loaded C:\tmp\mscordbi.dll\5B88589711f000\mscordbi.dll Loaded C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscordacwks.dll Dumping managed stack and managed variables using ICorDebug. ============================================================================= Child SP IP Call Site 0095edac 7782265c [NativeStackFrame] 0095ee28 72a631df 0095ee2c (null) [Managed to Unmanaged transition: 0095ee2c] 0095ee90 731a0163 [DEFAULT] I4 System.IO.__ConsoleStream.ReadFileNative(Class Microsoft.Win32.SafeHandles.SafeFileHandle,SZArray UI1,I4,I4,Boolean,Boolean,ByRef I4) (C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll) PARAMETERS: + (Error 0x80131304 retrieving parameter 'hFile') + (Error 0x80131304 retrieving parameter 'bytes') + (Error 0x80131304 retrieving parameter 'offset') + (Error 0x80131304 retrieving parameter 'count') + (Error 0x80131304 retrieving parameter 'useFileAPIs') + (Error 0x80131304 retrieving parameter 'isPipe') + (Error 0x80131304 retrieving parameter 'bytesRead') LOCALS: + (Error 0x80004005 retrieving local variable 'readSuccess') + (Error 0x80004005 retrieving local variable 'errorCode') + byte& p = 0 + (Error 0x80004005 retrieving local variable 'local_3') + (Error 0x80004005 retrieving local variable 'p') + (Error 0x80004005 retrieving local variable 'charsRead') 0095eec4 731a0072 [DEFAULT] [hasThis] I4 System.IO.__ConsoleStream.Read(SZArray UI1,I4,I4) (C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll) PARAMETERS: + (Error 0x80131304 retrieving parameter 'this') + (Error 0x80131304 retrieving parameter 'buffer') + (Error 0x80131304 retrieving parameter 'offset') + (Error 0x80131304 retrieving parameter 'count') LOCALS: + (Error 0x80004005 retrieving local variable 'bytesRead') + (Error 0x80004005 retrieving local variable 'errCode') 0095eee4 72994dd7 [DEFAULT] [hasThis] I4 System.IO.StreamReader.ReadBuffer() (C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll) PARAMETERS: + System.IO.StreamReader this @ 0x2be4150 LOCALS: + (Error 0x80004005 retrieving local variable 'len') + (Error 0x80004005 retrieving local variable 'local_1') 0095eef4 72a14b18 [DEFAULT] [hasThis] String System.IO.StreamReader.ReadLine() (C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll) PARAMETERS: + System.IO.StreamReader this @ 0x2be4150 LOCALS: + (Error 0x80004005 retrieving local variable 'sb') + (Error 0x80004005 retrieving local variable 'i') + (Error 0x80004005 retrieving local variable 'ch') + (Error 0x80004005 retrieving local variable 's') 0095ef10 732e1c61 [DEFAULT] [hasThis] String System.IO.TextReader+SyncTextReader.ReadLine() (C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll) PARAMETERS: + System.IO.TextReader+SyncTextReader this @ 0x2be44d0 LOCALS: (none) 0095ef20 73148310 [DEFAULT] String System.Console.ReadLine() (C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll) PARAMETERS: (none) LOCALS: (none) 0095ef28 00d204eb [DEFAULT] Void ConsoleApp.Program.Bar(Object) (C:\Users\adafurma\source\repos\ConsoleApp3\ConsoleApp3\bin\Debug\ConsoleApp3.exe) PARAMETERS: + ConsoleApp.Foo foo @ 0x2be23b8 LOCALS: (none) 0095ef3c 00d20498 [DEFAULT] Void ConsoleApp.Program.Main() (C:\Users\adafurma\source\repos\ConsoleApp3\ConsoleApp3\bin\Debug\ConsoleApp3.exe) PARAMETERS: (none) LOCALS: + ConsoleApp.Foo foo @ 0x2be23b8 + (Error 0x80004005 retrieving local variable 'local_1') 0095ef50 73a9ebb6 [NativeStackFrame] Stack walk complete. ============================================================================= |
1 2 3 |
0:000> !do 0x2be23b8 <Note: this object has an invalid CLASS field> Invalid object |
So when we try to dump the object it indicates that it is incorrect. Why? Well, let’s see raw content:
1 2 3 4 5 6 7 8 9 |
0:000> dd 0x2be23b8 02be23b8 00000000 80000000 72a9eb40 0000000b 02be23c8 006f0053 0065006d 00730020 00720074 02be23d8 006e0069 00000067 00000000 72aac29c 02be23e8 00000000 00000000 00000000 00000000 02be23f8 00000000 00000000 72aa14c8 00000000 02be2408 02be2430 02be2440 000004b0 00000100 02be2418 00000000 00000000 72a9eb40 00000001 02be2428 0000fffd 00000000 72aa1768 00000000 |
So it shows value, not the reference. The pointer is a bit misleading. Let’s dump the whole stack around the function:
1 2 3 4 5 6 7 8 9 |
0:000> dd 0095ef3c 0095ef3c 02be23b4 02be23b4 00000000 0095ef54 0095ef4c 73a9ebb6 00b69bd8 0095efa8 73aa1e10 0095ef5c 0095efe4 0095ef98 73b79b20 0095f0b8 0095ef6c 73aa1dc9 a60effde 0095f104 0095f078 0095ef7c 0095f02c 00c94d34 0095efe4 00000000 0095ef8c a60effde 0095ef60 0095f078 0095f12c 0095ef9c 73b889e0 d5310e5e 00000001 0095f010 0095efac 73aa7994 00000000 00000000 00000001 |
And now let’s dump the raw pointer (did you notice that the address is 0x2be23b8 – 4 ?)
1 2 3 4 5 6 7 8 |
0:000> !do 02be23b4 Name: ConsoleApp.Foo MethodTable: 00c94dbc EEClass: 00c916f8 Size: 12(0xc) bytes File: C:\Users\adafurma\source\repos\ConsoleApp3\ConsoleApp3\bin\Debug\ConsoleApp3.exe Fields: None |
And now you can clearly see that the MT address is the same as shown earlier.
There is a lot of trickery around value types, especially when it comes to enums. See this post describing some of it.
41. What is the base class of the delegate?
See this.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
using System; public class Program { delegate void X(); public static void Main() { X x = Foo; Console.WriteLine(x.GetType().BaseType); Console.WriteLine(x.GetType().BaseType.BaseType); Console.WriteLine(x.GetType().BaseType.BaseType.BaseType); } static void Foo(){} } |
Output:
1 2 3 |
System.MulticastDelegate System.Delegate System.Object |
It is MulticastDelegate
which in turn inherits from Delegate
which inherits from object. MulticastDelegate
contains a list of delegates.
42. What is the base class of an array?
See this code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
using System; public class Program { public static void Main() { Foo[] foo = new Foo[5]; Console.WriteLine(foo.GetType().BaseType); foreach(var type in foo.GetType().GetInterfaces()){ Console.WriteLine(type); } } } class Foo{ } |
It shows the following:
1 2 3 4 5 6 7 8 9 10 11 12 |
System.Array System.ICloneable System.Collections.IList System.Collections.ICollection System.Collections.IEnumerable System.Collections.IStructuralComparable System.Collections.IStructuralEquatable System.Collections.Generic.IList`1[Foo] System.Collections.Generic.ICollection`1[Foo] System.Collections.Generic.IEnumerable`1[Foo] System.Collections.Generic.IReadOnlyList`1[Foo] System.Collections.Generic.IReadOnlyCollection`1[Foo] |
So whenever you create an array, .NET creates a class for you and implements quite a lot of interfaces. But is it always the same? Check this code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
using System; public class Program { public static void Main() { Foo[,] foo = new Foo[5,4]; Console.WriteLine(foo.GetType().BaseType); foreach(var type in foo.GetType().GetInterfaces()){ Console.WriteLine(type); } } } class Foo{ } |
It shows
1 2 3 4 5 6 7 |
System.Array System.ICloneable System.Collections.IList System.Collections.ICollection System.Collections.IEnumerable System.Collections.IStructuralComparable System.Collections.IStructuralEquatable |
We don’t have generic interfaces here. What about pointers?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
using System; public class Program { public static void Main() { unsafe { int *[] foo = new int *[5]; Console.WriteLine(foo.GetType().BaseType); foreach (var type in foo.GetType().GetInterfaces()) { Console.WriteLine(type); } } } } |
1 2 3 4 5 6 7 |
System.Array System.ICloneable System.Collections.IList System.Collections.ICollection System.Collections.IEnumerable System.Collections.IStructuralComparable System.Collections.IStructuralEquatable |
Again, no generic interfaces.
43. Can you make a 2-based array?
Use this code:
1 2 3 4 5 6 7 8 9 10 11 12 |
using System; public class Program { public static void Main() { Array array = Array.CreateInstance(typeof(int), new int[]{1}, new int[]{2}); array.SetValue(123, 2); Console.WriteLine(array.GetValue(2)); Console.WriteLine(array.GetValue(0)); } } |
Output:
1 2 3 4 5 6 7 8 9 |
123 Run-time exception (line -1): Index was outside the bounds of the array. Stack Trace: [System.IndexOutOfRangeException: Index was outside the bounds of the array.] at System.Array.InternalGetReference(Void* elemRef, Int32 rank, Int32* pIndices) at System.Array.GetValue(Int32 index) at Program.Main() |
You can see that accessing index 0 throws exception.
44. What is a string interning?
It’s a way of deduplicating strings in your application. You can ask .NET to check if a string of given content was already created and reuse it. See this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
using System; using System.Text; public class Program { public static void Main() { String s1 = "MyTest"; String s2 = new StringBuilder().Append("My").Append("Test").ToString(); String s3 = String.Intern(s2); Console.WriteLine("s1 == '{0}'", s1); Console.WriteLine("s2 == '{0}'", s2); Console.WriteLine("s3 == '{0}'", s3); Console.WriteLine("Is s2 the same reference as s1?: {0}", (Object)s2==(Object)s1); Console.WriteLine("Is s3 the same reference as s1?: {0}", (Object)s3==(Object)s1); } } |
This prints:
1 2 3 4 5 |
s1 == 'MyTest' s2 == 'MyTest' s3 == 'MyTest' Is s2 the same reference as s1?: False Is s3 the same reference as s1?: True |