Skip to content

Commit 3fe0aab

Browse files
committed
Add details of union types to project README
1 parent 44cf79b commit 3fe0aab

File tree

1 file changed

+55
-1
lines changed

1 file changed

+55
-1
lines changed

README.md

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public sealed class Holiday
4444

4545
# Supported types
4646

47-
Both serialiser and deserialiser support the core built-in types of `byte`, `sbyte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `float`, `double`, `decimal`, `string`, as well as `DateTime`, `DateTimeOffset`, `TimeSpan`, `Guid`, `IntPtr`, `Version`, `Nullable<T>`, `IReadOnlyList<T>`, `IReadOnlyDictionary<TKey, TValue>`, `Tuple<...>` and enum types.
47+
Both serialiser and deserialiser support the core built-in types of `byte`, `sbyte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `float`, `double`, `decimal`, `string`, as well as `DateTime`, `DateTimeOffset`, `TimeSpan`, `Guid`, `IntPtr`, `Version`, `Nullable<T>`, `IReadOnlyList<T>`, `IReadOnlyDictionary<TKey, TValue>`, `Tuple<...>` and enum types. Additionally, a `Union<...>` type exists which allows a given field to take on one of a fixed number of known types.
4848

4949
Types may contain fields of further complex types, which are nested.
5050

@@ -180,6 +180,60 @@ new Deserialiser<Reindeer>(UnexpectedFieldBehaviour.Ignore).Deserialise(...);
180180

181181
---
182182

183+
# Union Types
184+
185+
Dasher is strict about the types it deals with. This allows great control over message schema versions, but sometime you don't know exactly which type you will need. Union types allow flexibility, but in a controlled fashion.
186+
187+
Dasher provides a `Union<T1,T2,...>` type. This allows a given field's type to be one of a set of known types.
188+
189+
Let's look at some examples. Firstly, construction of a union instance:
190+
191+
```csharp
192+
// implicit conversion
193+
Union<int, string> union1 = 1;
194+
Union<int, string> union2 = "Hello";
195+
196+
// alternatively, explicit construction
197+
var union1 = Union<int, string>.Create(1);
198+
var union2 = Union<int, string>.Create("Hello");
199+
```
200+
201+
There are a few ways to consume unions:
202+
203+
```csharp
204+
// consuming a union
205+
union1.Type // int
206+
union1.Value // 1 (boxed as object)
207+
208+
// perform an action based on type
209+
union1.Match(
210+
i => Console.WriteLine($"Union holds an int: {i}"),
211+
s => Console.WriteLine($"Union holds a string: {s}"));
212+
213+
// mapping based on type
214+
var num = union1.Match(
215+
i => i * 2,
216+
s => s.Length);
217+
```
218+
219+
The `Match` methods offer great performance as they won't box value types and don't involve any lookup based on type (beyond a single vtable lookup).
220+
221+
A class could have a property of type `Union<int, string>` and be successfully serialised and deserialised by Dasher. That property can contain either of these types.
222+
223+
This allows a controlled form of polymorphism (with base type requirement), and allows for heterogeneous lists/dictionaries. For example:
224+
225+
```csharp
226+
IReadOnlyList<Union<AddItemRequest, RemoveItemRequest>> Requests { get; }
227+
```
228+
229+
Unions are fully composable, so the above to could be inverted if you knew all items in the list would have the same type:
230+
231+
```csharp
232+
Union<IReadOnlyList<AddItemRequest>, IReadOnlyList<RemoveItemRequest>> Requests { get; }
233+
```
234+
235+
---
236+
183237
# Encoding
184238

185239
You don't _need_ to know how Dasher encodes messages in order to use it successfully, but a deeper understanding is never a bad thing.

0 commit comments

Comments
 (0)