in src/Cli/func/Extensions/GenericExtensions.cs [10:59]
public static TTarget MergeWith<TTarget, TSource, TSelected>(this TTarget target, TSource source, Func<TSource, TSelected> selector = null)
where TTarget : class
where TSource : class
where TSelected : class
{
object selectedSource = null;
if (source != null && selector != null)
{
selectedSource = selector(source);
}
if (selectedSource is null)
{
return target;
}
foreach (var sourceProperty in selectedSource.GetType().GetProperties())
{
var targetProperty = target.GetType().GetProperties().FirstOrDefault(p => p.Name.Equals(sourceProperty.Name, StringComparison.OrdinalIgnoreCase));
var targetPropertyEnum = target.GetType().GetProperties().FirstOrDefault(p => p.Name.Equals(sourceProperty.Name + "Enum", StringComparison.OrdinalIgnoreCase));
new List<PropertyInfo>() { targetProperty, targetPropertyEnum }.ForEach(property =>
{
if (property == null)
{
return;
}
var st = sourceProperty.PropertyType;
var tt = property.PropertyType;
Func<bool> validReadableProperties = () => (sourceProperty.CanRead && property.CanRead);
Func<bool> typesMatch = () => st == tt;
Func<bool> enumMatch = () => tt.IsEnum && Enum.GetUnderlyingType(tt) == st;
Func<bool> nullableEnumMatch = () => Nullable.GetUnderlyingType(tt) != null && Nullable.GetUnderlyingType(tt).IsEnum && Enum.GetUnderlyingType(Nullable.GetUnderlyingType(tt)) == st;
Func<bool> nullableMatch = () => Nullable.GetUnderlyingType(tt) == st;
if (validReadableProperties() && (typesMatch() || nullableMatch() || enumMatch()))
{
property.SetValue(target, sourceProperty.GetValue(selectedSource));
}
else if (validReadableProperties() && nullableEnumMatch())
{
property.SetValue(target, Enum.ToObject(Nullable.GetUnderlyingType(tt), sourceProperty.GetValue(selectedSource)));
}
});
}
return target;
}