Skip to content

Dynamic Row Converters

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

Dynamic Row Converters

Introduction

The DynamicRowConverter class provides a way to control what happens when a row read into a dynamic variable is cast to a static type. You obtain dynamic rows using an IReader<dynamic> or IAsyncReader<dynamic> created by a IBoundConfiguration<dynamic> you made with a call to Configuration.ForDynamic(Options).

There is one kind of cast that will always succeed, and will not consult a DynamicRowConverter - casts to IDisposable. This is to allow disposal to always function appropriately, whether done explicitly with calls to IDisposable.Dispose() or implicit with using statements.

The Default Type Describer supports common conversions and may be adequate for your needs.

Supported Backers

DynamicRowConverter instances can be backed by constructors, methods, and delegates.

Delegates and methods 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(DynamicRowConverter) the fallback will be tried.

Constructors

Three kinds of constructors are supported:

Constructors are assumed to never fail, and therefore will never fallback to another DynamicRowConverter. If a constructor is fallible, it should be wrapped in a method or delegate that detects failures and returns false.

Delegates

Any delegate of the form bool Name(object, in ReadContext, out DesiredType) can back a DynamicRowConverter.

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

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

Methods

Any static MethodInfo that exposes the same interface as DynamicRowConverterDelegate<TOutput> can back a DynamicRowConverter.

Concretely, the method must:

  • be static
  • return a bool
  • have 3 parameters
    • The first parameter must be dynamic or object
    • The second parameter must be in ReadContext
    • The third parameter must be an out parameter of the desired type

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

Chaining With Else(DynamicRowConverter)

Delegate and method backed DynamicRowConverters can fail, and indicate that by returning false. If Cesil cannot convert a row due to these failures, an exception will be raised.

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

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

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

Explicit Casts

Cesil provides explicit casts from ConstructorInfo, MethodInfo, and Delegate to DynamicRowConverter. These are roughly equivalent to calling the static ForXXX(...) methods on DynamicRowConverter, but differ in a few ways.

For all explicit casts, unlike the ForXXX(...) methods, null values are allowed (returning null themselves).

The ConstructorInfo explicit cast only accepts constructors that accept a single object or dynamic parameter, other types of constructors must use the appropriate ForXXX(...) methods.

The Delegate explicit cast accepts non-DynamicRowConverterDelegate<TOutput> delegates, unlike the DynamicRowConverter.ForDelegate<TOutput>(DynamicRowConverterDelegate<TOutput>) method.