-
Notifications
You must be signed in to change notification settings - Fork 4
Document Conversion
Suppose we need to convert the class Source
to the class Dest
.
public class Source
{
public string Email { get; set; }
public string UserId { get; set; }
public Tuple<string, string>[] Properties { get; set; }
}
public class Dest
{
public string Login { get; set; }
public Guid UserId { get; set; }
public KeyValuePair<string, string>[] Properties { get; set; }
}
We should create a class derived from the abstract class ConverterCollection<TSource, TDest>
, which exposes a public method GetConverter
that returns Func<TSource, TDest>
– desired conversion function.
Then we are expected to provide an implementation for abstract method Configure
.
This method should contain conversion rules, which could be set using the configurator
parameter.
public class ExampleConverterCollection : ConverterCollection<Source, Dest>
{
public UserConverterCollection(IPathFormatterCollection pathFormatterCollection,
IStringConverter stringConverter)
: base(pathFormatterCollection, stringConverter)
{
}
protected override void Configure(MutatorsContext context,
ConverterConfigurator<Source, Dest> configurator)
{
configurator.Target(dest => dest.Login)
.Set(source => source.Email);
configurator.Target(dest => dest.UserId)
.Set(source => Guid.Parse(source.UserId));
configurator.Target(dest => dest.Properties.Each().Key)
.Set(source => source.Properties.Current().Item1);
configurator.Target(dest => dest.Properties.Each().Value)
.Set(source => source.Properties.Current().Item2);
}
}
We use the configurator's method Target
to provide a path to a property, to which we want to set a value.
The Set
method is used to provide a function returning a value to set.
The Target
method takes as a parameter a lambda expression with a single argument of type Dest
, while Set
method takes a lambda expression with a parameter of type Source
.
Note that the Target
must be called before the Set
method.
As you can see in the example above we use the Each
method to mark the destination array inside the lambda of the Target
method and we use the Current
method inside the Set
method to mark the source enumerable for the conversion.
This construction tells us that the kth item of the destination array will receive a value from the kth item of the source array.
These methods are extensions methods that take an Enumerable<T>
and return a value of T
, so you can continue to write a path to a property of an arra item.
They are not invoked during the execution of conversion function, but serve as substitues for corresponding indices of the source array and the destination array.
If you need to convert an array that is inside of an item of another array you simply should call Each
and Current
methods after going through each property of an array type.
For example:
configurator.Target(dest => dest.Users.Each().Properties.Each().Value)
.Set(source => source.UserInfos.Current().Values.Current());
A conversion rule can depend on a condition involving some TSource
properties.
Mutators allow to define such conversions using the If
method:
configurator.If(source => source.IsLegalEntity)
.Target(dest => dest.TaxNumber)
.Set(source => source.LegalEntityInfo.Inn);
configurator.If(source => !source.IsLegalEntity)
.Target(dest => dest.TaxNumber)
.Set(source => source.IndividualEntrepreneurInfo.Inn);
The If
method takes a condition represented by a lambda expression that returns a bool?
value.
The method returns a new ConverterConfigurator
instance that contains information about the applied condition.
All conversions created using this instance will happen if and only if the condition is satisfied.
If the If
method is applied multiple times, a conversion will happen if and only if all conditions passed to called If
methods are satisfied.
Goto
is a method which helps to get rid of a boilerplate code.
Instead of writing long and slightly different paths from the root of the document, you can travel to a node of the document tree and define conversion rules for a subtree of this node.
var valuesConfigurator = configurator.GoTo(dest => dest.Properties.Each(),
source => source.Properties.Current());
valuesConfigurator.Target(dest => dest.Key)
.Set(source => source.Item1);
valuesConfigurator.Target(dest => dest.Key)
.Set(source => source.Item2);
Goto
method returns a new ConverterConfigurator
instance, which "remembered" a path to a node of document tree.
All configurator methods called on the new instance will take as parameters paths going from the corresponding document subtree root.
The example above shows how the Properties
array conversion can be rewritten using the Goto
method.
The ConverterConfigurator
class also has some handy overloads for the Set
method alongside with other useful methods defined in ConverterConfiguratorExtensions.
The PathFormatterCollection
parameter is irrelevant in the context of a simple document conversion, so you can simply pass a new PathFormatterCollection
as the constructor parameter.
It is used when a field or a property you convert requires a preliminary validation (see [TODO: link to validation before conversion]).
The StringConverter
parameter is used only for a custom fields conversion, so if you don't use custom fields, you can simply pass null
as the corresponding constructor parameter.
The MutatorsContext
is a parameter of the Configure
method, which is used to customize a conversion ruleset. See more on MutatorsContext page.
You can find more conversion examples in converter collections in functional tests.