This is part 15/17 of my Exploring the .NET CoreFX series.
While C# supports type inference for generic methods, it does not support type inference for constructors. In other words, while this code works:
|
|
This code does not:
Read more...This is part 15/17 of my Exploring the .NET CoreFX series.
While C# supports type inference for generic methods, it does not support type inference for constructors. In other words, while this code works:
|
|
This code does not:
Read more...This is part 14/17 of my Exploring the .NET CoreFX series.
Back in 2013, Immo Landwerth and Andrew Arnott recorded a Going Deep video called Inside Immutable Collections which describes how and why System.Collections.Immutable is built the way it is. It’s great background material to understand System.Collections.Immutable.
This is part 13/17 of my Exploring the .NET CoreFX series.
Most implementations of IList
, including System.Collections.Generic.List
, are dynamic arrays. System.Collections.Immutable.ImmutableList
is different – it is an AVL tree. This results in significantly different performance characteristics:
List |
ImmutableList |
|
---|---|---|
Indexing | O(1) | O(log n) |
Append | O(1) average, O(n) worst-case | O(log n) |
Insert at arbitrary index | O(n) | O(log n) |
Remove | O(n) | O(log n) |
Memory layout | Contiguous for value types | Non-contiguous |
The data structure behind ImmutableList
was likely chosen so that modifications to the list are non-destructive and require minimal data copying.
This is part 12/17 of my Exploring the .NET CoreFX series.
In C++, the inline
keyword allows a developer to provide a hint to the compiler that a particular method should be inlined. C# has the identical ability but uses an attribute instead:
|
|
In System.Collections.Immutable, this attribute is used highly selectively – only once, in fact.
Read more...This is part 11/17 of my Exploring the .NET CoreFX series.
In 2008, Microsoft Research published Code Contracts, which provide a language-agnostic way to express coding assumptions in .NET programs. The assumptions take the form of pre-conditions, post-conditions, and object invariants.
Here is a simple example of code which uses Code Contracts:
|
|
Code Contracts assertions are not limited to runtime enforcement. They may instead be enforced by compile-time static analysis. For example, it is very simple to annotate methods with Code Contracts, set up a continuous integration (CI) server to perform static analysis, and fail the build if there are any failed assertions. This gives us the best of both worlds: a guarantee our code enforces our assumptions with essentially zero runtime penalty.
Read more...This is part 10/17 of my Exploring the .NET CoreFX series.
The .NET Core’s System.Collections.Immutable.ImmutableArray
provides two enumerators. The first has been highly tuned for speed, and the second is a fallback for compatibility when it is required.
The high-performance enumerator uses the following performance optimizations:
struct
, rather than a class
, so that it is stack-allocated rather than heap-allocated.IEnumerator
or IEnumerator
, as this would require it to implement IDisposable
. By not implementing IDisposable
the iterator will inline during foreach
loops..Enumerator.Current
; it requires on .NET’s array range checks to throw an exception instead.The high-performance enumerator is called ImmutableArray.Enumerator
, which is returned by ImmutableArray.GetEnumerator()
:
This is part 9/17 of my Exploring the .NET CoreFX series.
Using the builder pattern to allow for easier construction of immutable objects is well-known.
The .NET Core’s immutable collections assembly, System.Collections.Immutable
, also uses the builder pattern, but for a slightly different reason: to improve the performance of making many changes to the collection. This is possible because, unlike the immutable collection itself, the builder pattern does not need to maintain the immutable collection’s invariants after each modification. The builder pattern merely needs to reestablish the invariants of the immutable collection upon the publishing of the results.
This is part 8/17 of my Exploring the .NET CoreFX series.
The .NET Core’s System.Collections.Immutable.ImmutableArray
class implements an immutable wrapper around a normal C# managed array. This looks something like:
|
|
ImmutableArray.array
is lazy-initialized.
Within the ImmutableArray
class, there are a number of methods which have the precondition that ImmutableArray.array
must be initialized. These preconditions must be checked before the method begins processing to make sure we handle invalid states correctly.
This is part 7/17 of my Exploring the .NET CoreFX series.
In the previous post, I referenced EqualityComparer.Default
. If T
does not implement IEquatable
, EqualityComparer.Default
will use the framework-defined Object.Equals()
, which implements reference equality.
However, many times you want to compare two types for structural equality (i.e. identical content) rather than reference equality (i.e. two references point to the same instance of the class). The interface IStructuralEquatable
was defined to allow a class to explicitly implement structural, rather than reference equality. Related classes include IStructuralComparable
and StructuralComparisons
.
This is part 6/17 of my Exploring the .NET CoreFX series.
Let’s say you are writing a custom IList
which contains the following code:
|
|
The above code uses T
“s implementation of Object.Equals()
, which is defined as: