Skip to content

Type Conversion

Drew Noakes edited this page Mar 23, 2017 · 3 revisions

In certain cases, .NET types may differ between serialiser and deserialiser. Understanding these rules allows the graceful evolution of schema over time.

Here we consider the types of:

  • complex type properties
  • tuple member

Legend:

πŸŒ• always succeeds
πŸŒ‘ always fails
🌘 depends upon value

Conversions that depend upon the value can not be relied upon unless you know 100% that out-of-range values will not be serialised.

Dasher Conversions

Left column shows the input (serialised) type. Top row shows output (deserialised) types.

Byte SByte Int16 UInt16 Int32 UInt32 Int64 UInt64 Single Double Decimal Boolean Char String Empty Byte[] ArraySegment<byte>
Byte 🌘 πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘
SByte 🌘 πŸŒ• 🌘 πŸŒ• 🌘 πŸŒ• 🌘 πŸŒ‘ πŸŒ‘ πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘
Int16 🌘 🌘 🌘 πŸŒ• 🌘 πŸŒ• 🌘 πŸŒ‘ πŸŒ‘ πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘
UInt16 🌘 🌘 🌘 πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘
Int32 🌘 🌘 🌘 🌘 🌘 πŸŒ• 🌘 πŸŒ‘ πŸŒ‘ πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘
UInt32 🌘 🌘 🌘 🌘 🌘 πŸŒ• πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘
Int64 🌘 🌘 🌘 🌘 🌘 🌘 🌘 πŸŒ‘ πŸŒ‘ πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘
UInt64 🌘 🌘 🌘 🌘 🌘 🌘 🌘 πŸŒ‘ πŸŒ‘ πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘
Single πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘
Double πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘
Decimal πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ 🌘 πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ‘
Boolean πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘
Char πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ 🌘 πŸŒ‘ πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ‘
String πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ 🌘 πŸŒ‘ πŸŒ‘ 🌘 🌘 πŸŒ‘
Empty πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘
Byte[] πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ•
ArraySegment<byte> πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ•

Some observations:

  • Widening integral types of the same sign always works.
  • Converting signed to unsigned integers never works all the time.
  • Converting unsigned to wider signed integral types always works.
  • Narrowing integral types only works if the value received fits within the new type.
  • float can always widen to double without loss of precision.
  • Integral types can always be converted to decimal without loss of precision.
  • string can only convert to char if the string has a single character.
  • decimal can convert to string as decimal values are encoded as strings during transport anyway. Conversely, string can convert to decimal if the string passes decimal.TryParse.
  • byte[] and ArraySegment<byte> are interchangeable.

In general, Dasher takes a very conservative view on conversions, actively enabling them when provably safe to do so. Cases that only work some of the time are artefacts of the MsgPack encoding used. MsgPack messages do contain some type information, but at a more restricted level than the .NET type system.

.NET Conversions

For contrast, here are the results for the same conversions using .NET's System.Convert.ChangeType(object, Type) method.

Byte SByte Int16 UInt16 Int32 UInt32 Int64 UInt64 Single Double Decimal Boolean Char String Empty Byte[] ArraySegment<byte>
Byte 🌘 πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ‘
SByte 🌘 πŸŒ• 🌘 πŸŒ• 🌘 πŸŒ• 🌘 πŸŒ• πŸŒ• πŸŒ• πŸŒ• 🌘 πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ‘
Int16 🌘 🌘 🌘 πŸŒ• 🌘 πŸŒ• 🌘 πŸŒ• πŸŒ• πŸŒ• πŸŒ• 🌘 πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ‘
UInt16 🌘 🌘 🌘 πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ‘
Int32 🌘 🌘 🌘 🌘 🌘 πŸŒ• 🌘 πŸŒ• πŸŒ• πŸŒ• πŸŒ• 🌘 πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ‘
UInt32 🌘 🌘 🌘 🌘 🌘 πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ• 🌘 πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ‘
Int64 🌘 🌘 🌘 🌘 🌘 🌘 🌘 πŸŒ• πŸŒ• πŸŒ• πŸŒ• 🌘 πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ‘
UInt64 🌘 🌘 🌘 🌘 🌘 🌘 🌘 πŸŒ• πŸŒ• πŸŒ• πŸŒ• 🌘 πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ‘
Single 🌘 🌘 🌘 🌘 🌘 🌘 🌘 🌘 πŸŒ• 🌘 πŸŒ• πŸŒ‘ πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ‘
Double 🌘 🌘 🌘 🌘 🌘 🌘 🌘 🌘 πŸŒ• 🌘 πŸŒ• πŸŒ‘ πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ‘
Decimal 🌘 🌘 🌘 🌘 🌘 🌘 🌘 🌘 πŸŒ• πŸŒ• πŸŒ• πŸŒ‘ πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ‘
Boolean πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ‘ πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ‘
Char 🌘 🌘 🌘 πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ• πŸŒ‘ πŸŒ‘ πŸŒ‘
String 🌘 🌘 🌘 🌘 🌘 🌘 🌘 🌘 🌘 🌘 🌘 🌘 πŸŒ‘ 🌘 🌘 πŸŒ‘
Empty πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ• πŸŒ• πŸŒ‘
Byte[] πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘
ArraySegment<byte> πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘ πŸŒ‘

These built-in conversions introduce policy, conventions and occasional loss of precision. Dasher may extend its conversion capabilities in future. Use the issue tracker for discussion.

Clone this wiki locally