Index: DamEngine/trunk/src/Deltares.DamEngine.Data/Standard/ObjectExtensions.cs =================================================================== diff -u -r4000 -r4052 --- DamEngine/trunk/src/Deltares.DamEngine.Data/Standard/ObjectExtensions.cs (.../ObjectExtensions.cs) (revision 4000) +++ DamEngine/trunk/src/Deltares.DamEngine.Data/Standard/ObjectExtensions.cs (.../ObjectExtensions.cs) (revision 4052) @@ -27,421 +27,420 @@ using System.Linq; using System.Reflection; -namespace Deltares.DamEngine.Data.Standard +namespace Deltares.DamEngine.Data.Standard; + +/// +/// Static class ObjectExtensions +/// +public static class ObjectExtensions { + public static readonly CultureInfo DefaultCulture = new CultureInfo("nl-NL"); + private const double threshold = 0.0000001; + /// - /// Static class ObjectExtensions + /// Tests two double values for equality with a default precision of /// - public static class ObjectExtensions + /// The first double value + /// The other double value to compare with + /// True when almost equal + public static bool AlmostEquals(this double double1, double double2) { - public static readonly CultureInfo DefaultCulture = new CultureInfo("nl-NL"); - private const double threshold = 0.0000001; + return AlmostEquals(double1, double2, threshold); + } - /// - /// 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) + /// + /// 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 AlmostEquals(double1, double2, threshold); + return true; } - /// - /// 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)) { - if (double.IsNaN(double1) && double.IsNaN(double2)) - { - return true; - } + return false; + } - if (double.IsNaN(double1) || double.IsNaN(double2)) - { - return false; - } + return (Math.Abs(double1 - double2) <= precision); + } - return (Math.Abs(double1 - double2) <= precision); + /// + /// Converts an object to another type. Also works with nullable types. The method can't. + /// + /// + /// Also works with nullable types and enums. The method can't do this. + /// + /// The type to converto to + /// The object to convert + /// The converted object + /// When is null and name="type"/> is value type and not nullable. + /// When an error occurs during conversion. + public static T ToType(this object value) + { + if (value == null) + { + ThrowIfValueType(); + + return default; } - /// - /// Converts an object to another type. Also works with nullable types. The method can't. - /// - /// - /// Also works with nullable types and enums. The method can't do this. - /// - /// The type to converto to - /// The object to convert - /// The converted object - /// When is null and name="type"/> is value type and not nullable. - /// When an error occurs during conversion. - public static T ToType(this object value) + return (T) value.ToType(typeof(T), DefaultCulture); + } + + /// + /// Converts an object to another type. + /// + /// + /// Also works with nullable types and enums. The method can't do this. + /// This method can also be used to downcast numeric values for example from string (double) value "12,0" to short 12 + /// When trying to convert a string to double and the dutch culture is set, then this method tries to + /// parse the string with custom logic. Because it occures that some string are not properly + /// changed according to the current culture. For instance in dbf files where numeric values are stored as + /// strings (for example "10,23") + /// Use this method with care when high performance is required it is not yet tested with large data sets + /// + /// The value to convert + /// The target type to convert to + /// + /// The converted type + /// When is null and is value type and not nullable. + /// When an error occurs during conversion. + public static object ToType(this object value, Type type, CultureInfo culture) + { + if (value == null) { - if (value == null) - { - ThrowIfValueType(); + ThrowIfValueType(type); - return default; - } - - return (T) value.ToType(typeof(T), DefaultCulture); + return null; } - /// - /// Converts an object to another type. - /// - /// - /// Also works with nullable types and enums. The method can't do this. - /// This method can also be used to downcast numeric values for example from string (double) value "12,0" to short 12 - /// When trying to convert a string to double and the dutch culture is set, then this method tries to - /// parse the string with custom logic. Because it occures that some string are not properly - /// changed according to the current culture. For instance in dbf files where numeric values are stored as - /// strings (for example "10,23") - /// Use this method with care when high performance is required it is not yet tested with large data sets - /// - /// The value to convert - /// The target type to convert to - /// - /// The converted type - /// When is null and is value type and not nullable. - /// When an error occurs during conversion. - public static object ToType(this object value, Type type, CultureInfo culture) + if (type.IsEnum) { - if (value == null) - { - ThrowIfValueType(type); + return value.ToEnumType(type); + } - return null; - } + object result = null; - if (type.IsEnum) + if (IsNullable(type)) + { + try { - return value.ToEnumType(type); + var nullableConverter = new NullableConverter(type); + type = nullableConverter.UnderlyingType; + result = Convert.ChangeType(value, type, CultureInfo.InvariantCulture); } - - object result = null; - - if (IsNullable(type)) + catch { - try - { - var nullableConverter = new NullableConverter(type); - type = nullableConverter.UnderlyingType; - result = Convert.ChangeType(value, type, CultureInfo.InvariantCulture); - } - catch - { - result = null; - } + result = null; } - else + } + else + { + try { - try + if (type == typeof(double) && value is string) { - if (type == typeof(double) && value is string) + if (Equals(culture, new CultureInfo("nl-NL"))) { - if (Equals(culture, new CultureInfo("nl-NL"))) - { - // TODO: Needs to be tested !! - // TODO: replace parsing with regular expression - // TODO: to make this more flexible make parser injectable through lambda's + // TODO: Needs to be tested !! + // TODO: replace parsing with regular expression + // TODO: to make this more flexible make parser injectable through lambda's - var tmp = value as string; - if (tmp.Contains(",") && !tmp.Contains(".")) // 1,5 -> 1.5 - { - value = tmp.Replace(",", "."); - } - else if (tmp.Contains(",") && tmp.Contains(".") && tmp.Length > 4 && !tmp.Contains(" ")) - { - // 100,000.00 -> 100000.00 - value = tmp.Replace(",", ""); - } - - //TODO: how to handle 100,000 english notation? Seems not to occur in most/mabye all situations + var tmp = value as string; + if (tmp.Contains(",") && !tmp.Contains(".")) // 1,5 -> 1.5 + { + value = tmp.Replace(",", "."); } - - result = value.Equals("NaN") ? Double.NaN : Convert.ChangeType(value, type, CultureInfo.InvariantCulture); - } - else - { - // value needs to be downcasted - - switch (type.Name) + else if (tmp.Contains(",") && tmp.Contains(".") && tmp.Length > 4 && !tmp.Contains(" ")) { - case "SByte": - case "Byte": - case "Int16": - case "UInt16": - case "Int32": - case "UInt32": - case "Int64": - case "UInt64": - object tmp = Convert.ChangeType(value, typeof(double), CultureInfo.InvariantCulture); - result = Convert.ChangeType(tmp, type); - break; - default: - result = Convert.ChangeType(value, type, CultureInfo.InvariantCulture); - break; + // 100,000.00 -> 100000.00 + value = tmp.Replace(",", ""); } + + //TODO: how to handle 100,000 english notation? Seems not to occur in most/mabye all situations } + + result = value.Equals("NaN") ? Double.NaN : Convert.ChangeType(value, type, CultureInfo.InvariantCulture); } - catch (Exception e) + else { - ThrowConversionException(value, type, e); + // value needs to be downcasted + + switch (type.Name) + { + case "SByte": + case "Byte": + case "Int16": + case "UInt16": + case "Int32": + case "UInt32": + case "Int64": + case "UInt64": + object tmp = Convert.ChangeType(value, typeof(double), CultureInfo.InvariantCulture); + result = Convert.ChangeType(tmp, type); + break; + default: + result = Convert.ChangeType(value, type, CultureInfo.InvariantCulture); + break; + } } } + catch (Exception e) + { + ThrowConversionException(value, type, e); + } + } - return result; + return result; + } + + /// + /// Convert the value to the enum type + /// + /// The value to convert. + /// The type to convert to. + /// Ignores the case if set to true + /// The enum + public static object ToEnumType(this object value, Type type, bool ignoreCase = false) + { + if (value == null) + { + throw new ArgumentNullException("value"); } - /// - /// Convert the value to the enum type - /// - /// The value to convert. - /// The type to convert to. - /// Ignores the case if set to true - /// The enum - public static object ToEnumType(this object value, Type type, bool ignoreCase = false) + if (!ignoreCase && !Enum.IsDefined(type, value)) { - if (value == null) - { - throw new ArgumentNullException("value"); - } + ThrowConversionException(value, type, null); + } - if (!ignoreCase && !Enum.IsDefined(type, value)) - { - ThrowConversionException(value, type, null); - } + var stringVal = value.ToString(); + object result = null; + try + { + result = Enum.Parse(type, stringVal, ignoreCase); + } + catch (Exception e) + { + ThrowConversionException(value, type, e); + } - var stringVal = value.ToString(); - object result = null; - try - { - result = Enum.Parse(type, stringVal, ignoreCase); - } - catch (Exception e) - { - ThrowConversionException(value, type, e); - } + return result; + } - return result; + /// + /// Convert the value to the enum type + /// + /// The enum type to convert to + /// The value to convert. + /// A translation dictionary to handle items that do not match a given string representation + /// The enum + public static T ToEnumType(this object value, IDictionary lookup) + { + if (value == null) + { + throw new ArgumentNullException("value"); } - /// - /// Convert the value to the enum type - /// - /// The enum type to convert to - /// The value to convert. - /// A translation dictionary to handle items that do not match a given string representation - /// The enum - public static T ToEnumType(this object value, IDictionary lookup) + var stringVal = value.ToString(); + if (lookup != null && lookup.ContainsKey(stringVal)) { - if (value == null) + return lookup[stringVal]; + } + + return (T) ToEnumType(value, typeof(T)); + } + + /// + /// 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 (PropertyInfo destinationProperty in destination.GetType().GetProperties()) + { + var excluded = false; + foreach (string excludedProperty in excludedProperties) { - throw new ArgumentNullException("value"); + if (excludedProperty.ToLower().Equals(destinationProperty.Name.ToLower())) + { + excluded = true; + } } - var stringVal = value.ToString(); - if (lookup != null && lookup.ContainsKey(stringVal)) + if (excluded || IsIList(destinationProperty) || IsIDictionary(destinationProperty) + || IsGenericIList(destinationProperty) || IsGenericIDictionary(destinationProperty)) { - return lookup[stringVal]; + continue; } - return (T) ToEnumType(value, typeof(T)); + // 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)); + } } + } - /// - /// 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) + /// + /// 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 translator) + { + if (pInfo != null && pInfo.CanWrite) { - // Instantiate if necessary - if (destination == null) + if (translator != null) { - throw new ArgumentNullException("destination", "Destination object must first be instantiated."); + pInfo.SetValue(dest, translator(value), null); } - - // Loop through each property in the destination - foreach (PropertyInfo destinationProperty in destination.GetType().GetProperties()) + else { - var excluded = false; - foreach (string excludedProperty in excludedProperties) + if (pInfo.PropertyType.IsEnum) { - if (excludedProperty.ToLower().Equals(destinationProperty.Name.ToLower())) + try { - excluded = true; + object v = Enum.Parse(pInfo.PropertyType, value.ToString(), true); + pInfo.SetValue(dest, v, null); } - } + catch (Exception e) + { + string msg = string.Format( + "Couldn't parse value '{1}' to type {0}. Try to set a translation rule for this conversion.", + pInfo.PropertyType, value); - if (excluded || IsIList(destinationProperty) || IsIDictionary(destinationProperty) - || IsGenericIList(destinationProperty) || IsGenericIDictionary(destinationProperty)) - { - continue; + throw new ConversionException(msg, e); + } } - - // 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) + else { - 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)); + pInfo.SetValue(dest, ToType(value, pInfo.PropertyType), null); } } } + } - /// - /// 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 translator) + /// + /// Converts an object to another type. + /// + /// The value. + /// The type. + /// + /// is null and is value type and not nullable. + /// When an error occurs during conversion. + public static object ToType(this object value, Type type) + { + if (value == null) { - if (pInfo != null && pInfo.CanWrite) - { - if (translator != null) - { - pInfo.SetValue(dest, translator(value), null); - } - else - { - if (pInfo.PropertyType.IsEnum) - { - try - { - object v = Enum.Parse(pInfo.PropertyType, value.ToString(), true); - pInfo.SetValue(dest, v, null); - } - catch (Exception e) - { - string msg = string.Format( - "Couldn't parse value '{1}' to type {0}. Try to set a translation rule for this conversion.", - pInfo.PropertyType, value); + ThrowIfValueType(type); - throw new ConversionException(msg, e); - } - } - else - { - pInfo.SetValue(dest, ToType(value, pInfo.PropertyType), null); - } - } - } + return null; } - /// - /// Converts an object to another type. - /// - /// The value. - /// The type. - /// - /// is null and is value type and not nullable. - /// When an error occurs during conversion. - public static object ToType(this object value, Type type) - { - if (value == null) - { - ThrowIfValueType(type); + return value.ToType(type, DefaultCulture); + } - return null; - } + private static bool IsGenericIDictionary(PropertyInfo destinationProperty) + { + return destinationProperty.PropertyType.IsGenericType && destinationProperty.PropertyType.GetGenericTypeDefinition() == typeof(IDictionary<,>); + } - return value.ToType(type, DefaultCulture); - } + private static bool IsIDictionary(PropertyInfo destinationProperty) + { + return typeof(IDictionary).IsAssignableFrom(destinationProperty.PropertyType); + } - private static bool IsGenericIDictionary(PropertyInfo destinationProperty) - { - return destinationProperty.PropertyType.IsGenericType && destinationProperty.PropertyType.GetGenericTypeDefinition() == typeof(IDictionary<,>); - } + private static bool IsGenericIList(PropertyInfo destinationProperty) + { + return destinationProperty.PropertyType.IsGenericType && destinationProperty.PropertyType.GetGenericTypeDefinition() == typeof(IList<>); + } - private static bool IsIDictionary(PropertyInfo destinationProperty) - { - return typeof(IDictionary).IsAssignableFrom(destinationProperty.PropertyType); - } + private static bool IsIList(PropertyInfo destinationProperty) + { + return typeof(IList).IsAssignableFrom(destinationProperty.PropertyType); + } - private static bool IsGenericIList(PropertyInfo destinationProperty) - { - return destinationProperty.PropertyType.IsGenericType && destinationProperty.PropertyType.GetGenericTypeDefinition() == typeof(IList<>); - } + /// + /// Throws an ArgumentNullException if target type to convert to is a ValueType. + /// + /// + private static void ThrowIfValueType() + { + ThrowIfValueType(typeof(T)); + } - private static bool IsIList(PropertyInfo destinationProperty) + /// + /// Throws an ArgumentNullException if target type to convert to is a ValueType. + /// + /// The type. + private static void ThrowIfValueType(Type type) + { + if (type.IsValueType && !IsNullable(type)) { - return typeof(IList).IsAssignableFrom(destinationProperty.PropertyType); + throw new ArgumentNullException( + string.Format("The value can't be null because parameter type {0} is a value type", type)); } + } - /// - /// Throws an ArgumentNullException if target type to convert to is a ValueType. - /// - /// - private static void ThrowIfValueType() - { - ThrowIfValueType(typeof(T)); - } + /// + /// Determines whether the specified type is nullable. + /// + /// The type. + /// + /// true if the specified type is nullable; otherwise, false. + /// + private static bool IsNullable(Type type) + { + return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); + } - /// - /// Throws an ArgumentNullException if target type to convert to is a ValueType. - /// - /// The type. - private static void ThrowIfValueType(Type type) + /// + /// Throws conversion exception. + /// + /// The value. + /// The type. + /// The exception. + private static void ThrowConversionException(object value, Type type, Exception e) + { + var v = ""; + try { - if (type.IsValueType && !IsNullable(type)) - { - throw new ArgumentNullException( - string.Format("The value can't be null because parameter type {0} is a value type", type)); - } + v = value.ToString().Replace("\0", " "); } - - /// - /// Determines whether the specified type is nullable. - /// - /// The type. - /// - /// true if the specified type is nullable; otherwise, false. - /// - private static bool IsNullable(Type type) + catch { - return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); + throw new ConversionException(type, value.ToString(), e); } - /// - /// Throws conversion exception. - /// - /// The value. - /// The type. - /// The exception. - private static void ThrowConversionException(object value, Type type, Exception e) - { - var v = ""; - try - { - v = value.ToString().Replace("\0", " "); - } - catch - { - throw new ConversionException(type, value.ToString(), e); - } - - throw new ConversionException(type, v, e); - } + throw new ConversionException(type, v, e); } } \ No newline at end of file