RaspberryIO/Unosquare.Swan.Lite/Components/ObjectMap.cs
2019-12-04 17:10:06 +01:00

117 lines
4.3 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Unosquare.Swan.Abstractions;
namespace Unosquare.Swan.Components {
/// <summary>
/// Represents an object map.
/// </summary>
/// <typeparam name="TSource">The type of the source.</typeparam>
/// <typeparam name="TDestination">The type of the destination.</typeparam>
/// <seealso cref="Unosquare.Swan.Abstractions.IObjectMap" />
public class ObjectMap<TSource, TDestination> : IObjectMap {
internal ObjectMap(IEnumerable<PropertyInfo> intersect) {
this.SourceType = typeof(TSource);
this.DestinationType = typeof(TDestination);
this.Map = intersect.ToDictionary(
property => this.DestinationType.GetProperty(property.Name),
property => new List<PropertyInfo> { this.SourceType.GetProperty(property.Name) });
}
/// <inheritdoc/>
public Dictionary<PropertyInfo, List<PropertyInfo>> Map {
get;
}
/// <inheritdoc/>
public Type SourceType {
get;
}
/// <inheritdoc/>
public Type DestinationType {
get;
}
/// <summary>
/// Maps the property.
/// </summary>
/// <typeparam name="TDestinationProperty">The type of the destination property.</typeparam>
/// <typeparam name="TSourceProperty">The type of the source property.</typeparam>
/// <param name="destinationProperty">The destination property.</param>
/// <param name="sourceProperty">The source property.</param>
/// <returns>
/// An object map representation of type of the destination property
/// and type of the source property.
/// </returns>
public ObjectMap<TSource, TDestination> MapProperty
<TDestinationProperty, TSourceProperty>(
Expression<Func<TDestination, TDestinationProperty>> destinationProperty,
Expression<Func<TSource, TSourceProperty>> sourceProperty) {
PropertyInfo propertyDestinationInfo = (destinationProperty.Body as MemberExpression)?.Member as PropertyInfo;
if(propertyDestinationInfo == null) {
throw new ArgumentException("Invalid destination expression", nameof(destinationProperty));
}
List<PropertyInfo> sourceMembers = GetSourceMembers(sourceProperty);
if(sourceMembers.Any() == false) {
throw new ArgumentException("Invalid source expression", nameof(sourceProperty));
}
// reverse order
sourceMembers.Reverse();
this.Map[propertyDestinationInfo] = sourceMembers;
return this;
}
/// <summary>
/// Removes the map property.
/// </summary>
/// <typeparam name="TDestinationProperty">The type of the destination property.</typeparam>
/// <param name="destinationProperty">The destination property.</param>
/// <returns>
/// An object map representation of type of the destination property
/// and type of the source property.
/// </returns>
/// <exception cref="System.Exception">Invalid destination expression.</exception>
public ObjectMap<TSource, TDestination> RemoveMapProperty<TDestinationProperty>(
Expression<Func<TDestination, TDestinationProperty>> destinationProperty) {
PropertyInfo propertyDestinationInfo = (destinationProperty.Body as MemberExpression)?.Member as PropertyInfo;
if(propertyDestinationInfo == null) {
throw new ArgumentException("Invalid destination expression", nameof(destinationProperty));
}
if(this.Map.ContainsKey(propertyDestinationInfo)) {
_ = this.Map.Remove(propertyDestinationInfo);
}
return this;
}
private static List<PropertyInfo> GetSourceMembers<TSourceProperty>(Expression<Func<TSource, TSourceProperty>> sourceProperty) {
List<PropertyInfo> sourceMembers = new List<PropertyInfo>();
MemberExpression initialExpression = sourceProperty.Body as MemberExpression;
while(true) {
PropertyInfo propertySourceInfo = initialExpression?.Member as PropertyInfo;
if(propertySourceInfo == null) {
break;
}
sourceMembers.Add(propertySourceInfo);
initialExpression = initialExpression.Expression as MemberExpression;
}
return sourceMembers;
}
}
}