Skip to content

Formatters

kevin-montrose edited this page Apr 10, 2021 · 4 revisions

Formatters

Introduction

The Formatter class provides a way to control exactly what characters are written when serializing a cell of a particular type. Formatters are used in both static and dynamic serialization - in static serialization a Formatter is specified for an entire column, while in dynamic serialization the Formatter can vary per-cell.

There are a number of Default Formatters provided by Cesil, which may be adequate for your needs. They can be obtained with Formatter.GetDefault(TypeInfo).

Supported Backers

Formatter instances can be backed by methods and delegates. Both return a bool value where true indicates success and false indicates failure. If a delegate or method fails and a fallback has been configured with Else(Formatter) the fallback will be tried.

Delegates

Any delegate of the form bool Name(FormattingType, in WriteContext, IBufferWriter<char>) can back a Formatter.

Cesil provides FormatterDelegate<TValue> and Formatter.ForDelegate<TValue>(FormatterDelegate<TValue>) which conform to this form. You can also explicitly cast any delegate to Formatter, provided it is logically equivalent to FormatterDelegate<TValue>.

If a delegate backed Formatter returns false, the Formatter configured by Else(Formatter) (if any) will be tried next.

Methods

Any static MethodInfo that exposes the same interface as FormatterDelegate<TValue> can back a Formatter.

Concretely, the method must:

  • be static
  • return a bool
  • have 3 parameters

If a method backed Formatter returns false, the Formatter configured by Else(Formatter) (if any) will be tried next.

Defaults

Cesil provides a number of Default Formatters, obtainable with Formatter.GetDefault(TypeInfo).

These Formatters all correctly report failure, and thus support chaining.

Chaining With Else(Formatter)

Formatters can fail, indicated by it's backer returning false. If Cesil cannot format a value, an exception will be raised.

To try another Formatter after one fails, you chain them with the Else(Formatter) method. Else(Formatter) specifies which Formatter to try if the current one fails.

In order to support this behavior, a failing Formatter must not write to the IBufferWriter<char>. Requesting a Span<char> or Memory<char> does not count as a write, Advance(int) "commits" to writing. Be aware of helper methods that call Advance(int) internally, as they may write even in a failure case.

Else(Formatter) returns a new Formatter, the original is not modified.

If a Formatter already has a fallback Formatter specified, the one passed to Else(Formatter) will be tried after all the others have failed. Conceptually, Else(Formatter) adds a Formatter to the end of a list of fallbacks to try.

Explicit Casts

Cesil provides explicit casts of MethodInfo, and Delegate to Formatter. These are roughly equivalent to calling the static ForXXX(...) methods on Formatter, but differ by allowing null values.