-
Notifications
You must be signed in to change notification settings - Fork 1
Fluent Interface Comparer Configuration
One of the available ways to customize per-property object comparison is using a comparer configuration object. This object is designed with fluent interface in mind in order to simplify its use.
IMPORTANT: This type of configuration is local. This means that configuration made via the comparer configuration object is stored locally inside the the configuration object and does not affect any of the configuration data stored inside the scanner's data cache. Object comparer objects created with the configuration object will use the values configured via this method. Any configuration done via this method is not persisted globally in any way and does not affect the creation of other object comparer objects.
It may be possible that a specific configuration is needed in a specific place of an application, but another configuration is needed elsewhere in the application. In order to fulfill this requirement, this library provides a comparer configuration object that can be used to configure object comparers with configuration that is different from the one stored in the scanner's data cache.
CAUTION: An comparer configuration object allows the creation of object comparers for data types that are not registered in the scanner's cache. It accomplishes this by internally requesting the scanner to scan the type, but without asking the scanner to save the collected data in its data cache. This means that creating the comparer configuration object for data types not previously scanned will incur in a performance hit in your application. If the comparer configuration object is (re-)created often, then your application may suffer. Therefore, the recommendation is to always register all types beforehand with the scanner. See attributed configuration for details on how to register (scan) a type.
The helper class ComparerConfigurator provides the necessary methods to create the comparer configuration objects. The first step is to decide on the types that will be compared. Depending on the types, the appropriate overload is called:
//To create a configuration object for a comparer that compares objects of the same type:
var configSame = ComparerConfigurator.Configure<PurchaseOrder>();
//To create a configuration object for a comparer that compares objects of different types:
var configDiff = ComparerConfigurator.Configure<PurchaseOrder, PurchaseOrderVM>();IMPORTANT: While not necessary to pre-register the data types with the scanner, it is always recommended to avoid performance hits. A comparer configuration object will not cache any type of information in the scanner's cache, but it will certainly use it if available.
CONSEQUENCE: Because a comparer configuration object copies data from the scanner's cache, any copied data will come pre-configured with whatever configuration has been made globally using attributed configuration or fluent interface type configuration. If it is too much of a burden to "clean up" inherited property maps and whatnot, pass true to the ComparerConfigurator.Configure() method to re-scan the type ignoring all property maps and ignore attributes.
//To create a configuration object for a comparer that compares objects of the same type:
var configSame = ComparerConfigurator.Configure<PurchaseOrder>(true);
//To create a configuration object for a comparer that compares objects of different types:
var configDiff = ComparerConfigurator.Configure<PurchaseOrder, PurchaseOrderVM>(true);NOTE: Because the comparer configuration object is bound from step one to two data types, all configuration modifications will apply to the specified source and target types only.
Just call the IgnoreProperty() method of the comparer configuration object if you want to ignore a property during the per-property comparison routine. The property name is specified by writing a property LINQ expression.
Similarly, if a property map is needed, call the MapProperty() method. The property names of the source and destination are specified by writing a property LINQ expression.
Finally, if a custom comparer is needed, you may call the AddComparer() method with an object that implements the IComparer interface. This topic is not covered in this page, so if you want to know more about custom property value comparers, see the Property Value Comparison Customization page.
In the following example, configuration is provided for object comparers that can compare objects of type PurchaseOrder and PurchaseOrderVM.
After all configuration code has been specified, a call to CreateComparer() will instantiate the desired object comparer object.
ObjectComparer oc = ComparerConfigurator.Configure<PurchaseOrder, PurchaseOrderVM>()
.IgnoreProperty(src => src.Id)
.MapProperty(src => src.CreatedOn, dst => dst.SubmissionDate)
.MapProperty(src => src.ModifiedOn, dst => dst.ModifiedDate)
.AddComparer<DateTime>(new CustomDateComparer())
.CreateComparer();For more information about the comparison routine and comparison results, see Property Comparison Result Interpretation and Property Value Comparison Customization.