using System.Dynamic; using System.Reflection; namespace adas_core.Domain.Utils; public static class Mapper // We can only use reference types where T : class { private static readonly Dictionary PropertyMap; static Mapper() { // At this point we can convert each // property name to lower case so we avoid // creating a new string more than once. PropertyMap = typeof(T) .GetProperties() .ToDictionary( p => p.Name.ToLower(), p => p ); } /// /// Maps properties from an source to a strongly-typed destination object using a pre-defined property map. /// Property lookups are case-insensitive. Null values are only assigned to reference types or types; assigning null to a non-nullable value type throws. When a source value's type does not match the destination property's type, the value is converted using . /// /// The source whose key-value pairs will be mapped onto the destination. /// The target object that will receive the mapped property values. /// Thrown when or is null. /// Thrown when a source value is null but the corresponding destination property is a value type that is not . public static void Map(ExpandoObject source, T destination) { // Might as well take care of null references early. if (source == null) throw new ArgumentNullException(nameof(source)); if (destination == null) throw new ArgumentNullException(nameof(destination)); // By iterating the KeyValuePair of // source we can avoid manually searching the keys of // source as we see in your original code. foreach (var kv in source) if (PropertyMap.TryGetValue(kv.Key.ToLower(), out var p)) { var propType = p.PropertyType; if (kv.Value == null) { if (propType is { IsByRef: false } && propType.Name != "Nullable`1") // Throw if type is a value type // but not Nullable<> throw new ArgumentException("not nullable"); } else if (kv.Value.GetType() != propType) { // You could make this a bit less strict // but I don't recommend it. p.SetValue(destination, Convert.ToDouble(kv.Value), null); } p.SetValue(destination, kv.Value, null); } } }