/// <summary> /// Gets from cache (or creates and adds to cache) the <see cref="IODataMapper"/> (with option to merge alternate property configuration). /// </summary> private static IODataMapper GetOrCreateMapper(Type type, Dictionary <string, MemberInfo> altProps, string overrideEntityName) { if (_cache.TryGetValue(type, out IODataMapper map)) { return(map); } lock (_lock) { if (_cache.TryGetValue(type, out map)) { return(map); } if (!type.IsClass) { throw new MapperException($"Type '{type.Name}' must be a class for auto-mapping."); } var mea = type.GetCustomAttributes(typeof(MapperEntityAttribute), true).OfType <MapperEntityAttribute>().FirstOrDefault(); map = (IODataMapper)Activator.CreateInstance(typeof(ODataMapper <>).MakeGenericType(type), (overrideEntityName ?? mea?.Name) ?? type.Name); var pe = Expression.Parameter(type, "x"); string dname = null; var hasProperties = false; MapperPropertyAttribute mpa = null; foreach (var p in TypeReflector.GetProperties(type)) { // Do not auto-map where the Ignore attribute has been specified. if (p.GetCustomAttributes(typeof(MapperIgnoreAttribute), true).OfType <MapperIgnoreAttribute>().FirstOrDefault() != null) { continue; } // Get property merge config. if (altProps == null) { mpa = p.GetCustomAttributes(typeof(MapperPropertyAttribute), true).OfType <MapperPropertyAttribute>().FirstOrDefault(); dname = mpa?.Name; } else { if (!altProps.TryGetValue(p.Name, out MemberInfo alt)) { throw new InvalidOperationException($"Type '{type.Name}' Property '{p.Name}' does not have an alternative property configuration specified."); } // Do not auto-map where the Ignore attribute has been specified. if (alt.GetCustomAttributes(typeof(MapperIgnoreAttribute), true).OfType <MapperIgnoreAttribute>().FirstOrDefault() != null) { continue; } mpa = alt.GetCustomAttributes(typeof(MapperPropertyAttribute), true).OfType <MapperPropertyAttribute>().FirstOrDefault(); dname = mpa?.Name ?? alt.Name; } // Create the lambda expression for the property and add to the mapper. hasProperties = true; var lex = Expression.Lambda(Expression.Property(pe, p.Name), pe); var pmap = (IODataPropertyMapper)map.GetType() .GetMethod("Property", BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly) .MakeGenericMethod(p.PropertyType) .Invoke(map, new object[] { lex, dname, mpa == null ? OperationTypes.Any : mpa.OperationTypes }); if (mpa == null) { continue; } // Apply auto-map Property attribute IsUnique configuration. if (mpa.IsUniqueKey) { pmap.SetUniqueKey(mpa.IsUniqueKeyAutoGeneratedOnCreate); } // Apply auto-map Property attribute ConverterType configuration. if (mpa.ConverterType != null) { if (!typeof(IPropertyMapperConverter).IsAssignableFrom(mpa.ConverterType)) { throw new MapperException($"Type '{type.Name}' Property '{p.Name}' has 'MapperPropertyAttribute' with ConverterType set to '{mpa.ConverterType.Name}' which does not implement 'IPropertyMapperConverter'."); } IPropertyMapperConverter pmc = null; var pdef = mpa.ConverterType.GetProperty("Default", BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Static); if (pdef == null) { if (mpa.ConverterType.GetConstructor(Type.EmptyTypes) == null) { throw new MapperException($"Type '{type.Name}' Property '{p.Name}' has 'MapperPropertyAttribute' with ConverterType set to '{mpa.ConverterType.Name}' does not have a static 'Default' property or default constructor."); } pmc = (IPropertyMapperConverter)Activator.CreateInstance(mpa.ConverterType); } else { pmc = (IPropertyMapperConverter)pdef.GetValue(null); } pmap.SetConverter(pmc); continue; } // Apply auto-map Property attribute MapperType configuration for complex types. if (pmap.IsSrceComplexType) { IEntityMapperBase em = null; if (mpa.MapperType == null) { em = GetMapper(pmap.SrceComplexTypeReflector.ItemType); } else { if (!typeof(IEntityMapperBase).IsAssignableFrom(mpa.MapperType)) { throw new MapperException($"Type '{type.Name}' Property '{p.Name}' has 'MapperPropertyAttribute' with MapperType set to '{mpa.MapperType.Name}' which does not implement 'IEntityMapper'."); } var mdef = mpa.MapperType.GetProperty("Default", BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Static); if (mdef == null) { if (mpa.ConverterType.GetConstructor(Type.EmptyTypes) == null) { throw new MapperException($"Type '{type.Name}' Property '{p.Name}' has 'MapperPropertyAttribute' with MapperType set to '{mpa.MapperType.Name}' does not have a static 'Default' property or default constructor."); } em = (IEntityMapperBase)Activator.CreateInstance(mpa.MapperType); } else { em = (IEntityMapperBase)mdef.GetValue(null); } } if (em != null) { pmap.SetMapper(em); } } else if (mpa.MapperType != null) { throw new MapperException($"Type '{type.Name}' Property '{p.Name}' has 'MapperPropertyAttribute' with MapperType set to '{mpa.ConverterType.Name}' although the property is not a complex type."); } } if (!hasProperties) { throw new MapperException($"AutoMapper has found no properties for Type '{type.Name}' that it is able to auto-map."); } _cache.Add(type, map); return(map); } }
public static T MapTo <T>(this object from, params object[] ctorParameters) where T : class { if (from != null) { ConstructorInfo ctor = typeof(T).GetConstructor(ctorParameters.Select(p => p.GetType()).ToArray()); if (ctor == null) { throw new ArgumentException("Invalid Constructor Parameters"); } T result = (T)ctor.Invoke(ctorParameters); IEnumerable <PropertyInfo> properties = from.GetType().GetProperties() .Where(p => p.CanRead && !p.IsDefined(typeof(MapperIgnoreAttribute))); foreach (PropertyInfo property in properties) { try { MapperPropertyAttribute propAttribute = property.GetCustomAttribute <MapperPropertyAttribute>(); PropertyInfo resultProp = typeof(T).GetRuntimeProperty( propAttribute?.PropertyName ?? property.Name ); if ( resultProp != null && !resultProp.IsDefined(typeof(MapperIgnoreAttribute)) && resultProp.CanWrite ) { if (TypeDescriptor.GetConverter(property.PropertyType).CanConvertTo(resultProp.PropertyType)) { resultProp.SetValue(result, Convert.ChangeType(property.GetValue(from), resultProp.PropertyType)); } else if (property.PropertyType == typeof(string)) { if (resultProp.PropertyType == typeof(int)) { resultProp.SetValue(result, int.Parse(property.GetValue(from).ToString())); } else if (resultProp.PropertyType == typeof(DateTime)) { resultProp.SetValue(result, DateTime.Parse(property.GetValue(from).ToString())); } else if (resultProp.PropertyType == typeof(bool)) { resultProp.SetValue(result, bool.Parse(property.GetValue(from).ToString())); } else if (resultProp.PropertyType == typeof(double)) { resultProp.SetValue(result, double.Parse(property.GetValue(from).ToString())); } else if (resultProp.PropertyType == typeof(float)) { resultProp.SetValue(result, float.Parse(property.GetValue(from).ToString())); } } } } catch (Exception) { } } return(result); } else { return(null); } }