// Copyright (C) Stichting Deltares 2017. All rights reserved.
//
// This file is part of the Delta Shell Light Library.
//
// The Delta Shell Light Library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
// All names, logos, and references to "Deltares" are registered trademarks of
// Stichting Deltares and remain full property of Stichting Deltares at all times.
// All rights reserved.
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
namespace Deltares.DamEngine.Calculators.KernelWrappers.DamMacroStabilityCommon.Assemblers
{
public static class ObjectExtensions
{
public static readonly CultureInfo DefaultCulture = new CultureInfo("nl-NL");
private const double Threshold = 0.0000001;
///
/// Tests two double values for equality with a default precision of
///
/// The first double value
/// The other double value to compare with
/// True when almost equal
public static bool AlmostEquals(this double double1, double double2)
{
return AlmostEquals(double1, double2, Threshold);
}
///
/// Tests two double values for equality with a given precision
///
/// The first double value
/// The other double value to compare with
/// The precision value
/// True when almost equal
public static bool AlmostEquals(this double double1, double double2, double precision)
{
if (double.IsNaN(double1) && double.IsNaN(double2))
{
return true;
}
if (double.IsNaN(double1) || double.IsNaN(double2))
{
return false;
}
return (Math.Abs(double1 - double2) <= precision);
}
///
/// Clone properties from an original object to a destination object.
///
///
/// Copy matching properties from object to object
/// http://goneale.wordpress.com/2009/02/16/cloning-object-properties-via-reflection/#
///
///
///
///
///
public static void CloneProperties(this T1 origin, T2 destination, params string[] excludedProperties)
{
// Instantiate if necessary
if (destination == null)
{
throw new ArgumentNullException("destination", "Destination object must first be instantiated.");
}
// Loop through each property in the destination
foreach (var destinationProperty in destination.GetType().GetProperties())
{
bool excluded = false;
if (excludedProperties != null)
{
foreach (var excludedProperty in excludedProperties)
{
if (excludedProperty.ToLower().Equals(destinationProperty.Name.ToLower()))
{
excluded = true;
}
}
}
if (excluded || IsIList(destinationProperty) || IsIDictionary(destinationProperty)
|| IsGenericIList(destinationProperty) || IsGenericIDictionary(destinationProperty))
{
continue;
}
// find and set val if we can find a matching property name and matching type in the origin with the origin's value
if (!origin.Equals(default(T1)) && destinationProperty.CanWrite)
{
PropertyInfo propertyInfo = destinationProperty;
origin.GetType().GetProperties().Where(
x => x.CanRead && (x.Name == propertyInfo.Name && x.PropertyType == propertyInfo.PropertyType))
.ToList()
.ForEach(x => propertyInfo.SetValue(destination, x.GetValue(origin, null), null));
}
}
}
///
/// Performs a shallow clones the collections, matching collections on name and type.
///
/// Object type of the data origin.
/// Object type of the data target. Type is allowed to be
/// different from .
/// The origin object.
/// The destination object.
/// Collection properties of and
/// cannot be null.
/// destination;Destination object must first be instantiated.
public static void CloneCollections(this TSource origin, TTarget destination)
{
// Instantiate if necessary
if (destination == null)
{
throw new ArgumentNullException("destination", "Destination object must first be instantiated.");
}
// Loop through each property in the destination
foreach (var destinationProperty in destination.GetType().GetProperties())
{
var sourceProperty = origin.GetType().GetProperty(destinationProperty.Name);
if (sourceProperty != null)
{
if (IsIList(destinationProperty))
{
var target = (IList) destinationProperty.GetValue(destination, null);
var source = (IList) sourceProperty.GetValue(origin, null);
target.Clear();
foreach (var listItem in source)
{
target.Add(listItem);
}
}
if (IsGenericIList(destinationProperty))
{
var target = destinationProperty.GetValue(destination, null);
var source = (IEnumerable) sourceProperty.GetValue(origin, null);
// Get the ICollection interface part of the class, because Clear and Add are coming from this interface:
var genericICollectionImplementationType = typeof(ICollection<>).MakeGenericType(
destinationProperty.PropertyType.GetGenericArguments());
// Clear the target:
var genericICollectionClearMethod = genericICollectionImplementationType.GetMethod("Clear");
genericICollectionClearMethod.Invoke(target, null);
// Iterate through all items in source and shallow copy (add) them to the target:
var genericICollectionAddMethod = genericICollectionImplementationType.GetMethod("Add");
foreach (var listItem in source)
{
genericICollectionAddMethod.Invoke(target, new[]
{
listItem
});
}
}
else if (IsIDictionary(destinationProperty))
{
var target = (IDictionary) destinationProperty.GetValue(destination, null);
var source = (IDictionary) sourceProperty.GetValue(origin, null);
target.Clear();
foreach (var keyItem in source.Keys)
{
target[keyItem] = source[keyItem];
}
}
else if (IsGenericIDictionary(destinationProperty))
{
var target = destinationProperty.GetValue(destination, null);
var source = (IEnumerable) sourceProperty.GetValue(origin, null);
// Get the ICollection interface part of the class, because Clear is coming from this interface:
var genericICollectionImplementationType = typeof(ICollection<>).MakeGenericType(
typeof(KeyValuePair<,>).MakeGenericType(destinationProperty.PropertyType.GetGenericArguments()));
var genericICollectionClearMethod = genericICollectionImplementationType.GetMethod("Clear");
genericICollectionClearMethod.Invoke(target, null);
// Iterate through all items in source and shallow copy (add) them to the target:
var genericIDictionaryAddMethod = destinationProperty.PropertyType.GetMethod("Add");
foreach (var keyItem in source)
{
var key = keyItem.GetType().GetProperty("Key").GetValue(keyItem, null);
var value = keyItem.GetType().GetProperty("Value").GetValue(keyItem, null);
genericIDictionaryAddMethod.Invoke(target, new[]
{
key, value
});
}
}
}
}
}
///
/// Sets the object value.
///
///
/// The property info.
/// The destination object
/// The value
/// The translator
public static void SetObjectValue(this PropertyInfo pInfo, T dest, object value,
Func