.NET Internals Cookbook Part 11 — Various C# riddles

This is the eleventh 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

75. What is the TimeSpan resolution?

It’s 100 nanoseconds, as specified by the documentation:

76. What is shared between app domains?

Quite a few things:

  • Domain neutral Type objects
  • Reflection types like PropertyInfo
  • Strings
  • Threads

If you share one physical object between multiple app domains, it is called marshal-by-bleed. This is important because if you try locking such an object, you may effectively get a lock across different app domains. So if you do lock(typeof(Foo)) you may lock multiple app domains, which can be very nasty in ASP.NET applications (if you have multiple apps running on the same pool as they are separated by app domains).

On the other hand, if you want to share something in this way, see this code:

As a side note: .NET Core doesn’t expose app domains anymore. It uses them internally (at least one of them) but there is no API for it anymore.

77. Is Timer removed when there is no reference to it but it has callbacks?

Yes, it is. See this:

Output (with callback executed just once):

Documentation also mentions that:

78. What is the difference between delegate { ... } and delegate() { ... }?

The former accepts any parameters, the latter has no parameters at all. See this:

The last line doesn’t compile as you need to accept one parameter.

79. Can you have DllMain in C#?

You can’t in C#, but you can in IL. This is called Module Initializer. You just need to define a type initializer (static constructor) outside of any type (as we already know that you can have global methods and fields in IL):

This must be a type constructor. If you put an instance constructor you will get the following exception:

80. Can you implement your own Nullable< T>?

No. You can implement structure which would be similar in nature, with the same properties, but Nullable has special runtime support.

First, you cannot have Nullable of Nullable, even though the signature doesn’t prevent it:

Second, you cannot override GetType so you will have different results:

Output:

Third, you cannot assign null to instance of your type.

There are other differences around operators and method calls, so generally you can’t do that on your own.

81. Can you have more visible type inherit from less visible one?

You can do that with interfaces, see this:

It compiles and runs correctly.