Skip to content

Instance Providers

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

Instance Providers

Introduction

The InstanceProvider class provides a way to control how instances of a row are obtained during deserialization. InstanceProviders are only used during static deserialization.

Supported Backers

InstanceProvider 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(InstanceProvider) the fallback will be tried.

Constructors

Two kinds of constructors are supported, those taking zero parameters and those taking some set of parameters that have corresponding Setters.

You can create an InstanceProvider backed by a zero parameter constructor with the InstanceProvider.ForParameterlessConstructor(ConstructorInfo) method.

You can create an InstanceProvider backed by a constructor taking parameters with the InstanceProvider.ForConstructorWithParameters(ConstructorInfo) method. InstanceProvider of this kind will not be invoked until all values are available for the corresponding setters, and row reuse is not supported.

Constructors are assumed to never fail, and therefore will never fallback to another InstanceProvider. 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(in ReadContext, out DesiredType) can back an InstanceProvider.

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

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

Methods

Any static MethodInfo that exposes the same interface as InstanceProviderDelegate<TInstance> can back an InstanceProvider.

Concretely, the method must:

  • be static
  • return a bool
  • have 2 parameters
    • The first parameter must be in ReadContext
    • The second parameter must be an out parameter of the desired type

Use the InstanceProvider.ForMethod(MethodInfo) method to create a InstanceProvider backed by a method. You can also explicitly cast any MethodInfo to InstanceProvider, provided it is logically equivalent to InstanceProviderDelegate<TInstance>.

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

Defaults

For convenience, InstanceProvider has a GetDefault(TypeInfo) method which will return an InstanceProvider for any of the following:

  • All value types, the returned provider will create the default value
  • Reference types with a public zero parameter constructors, the returned provider will invoke the zero parameter constructor
  • string, the returned provider will create a null value
  • Version, the returned provider will create a null value
  • Uri, the returned provider will create a null value

These default InstanceProvider are used by the Default Type Describer to implement ITypeDescriber.GetInstanceProvider(TypeInfo).

Chaining With Else(InstanceProvider)

Delegate and method backed InstanceProviders can fail, and indicate that by returning false. If Cesil cannot obtain an instance due to these failures, an exception is raised.

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

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

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

Explicit Casts

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