internal IEnumerable <PropertyInfo> GetProperties(Type type, bool all = false) { var param = ConstructorToUse?.GetParameters(); if (param != null && param.Length > 0) { return(type .GetProperties() .Where(x => x.CanWrite | param.Any(p => p.Name.Equals( x.Name, StringComparison.InvariantCultureIgnoreCase)))); } return(type .GetProperties() .Where(x => x.CanWrite)); }
internal TypeMap(Type idAttribute) : base(typeof(T), idAttribute) { var type = typeof(T); var props = GetProperties(type); var fields = GetFields(type); var context = Parameter(typeof(MappingContext)); var prefix = Parameter(typeof(string)); var values = Parameter(typeof(List <Items>)); var first = Parameter(typeof(Items)); var constructorParams = ConstructorToUse?.GetParameters(); var defaultObject = (constructorParams?.Length ?? 0) == 0 ? Activator.CreateInstance <T>() : default; (MethodCallExpression, MemberInfo) Process( string propOrFieldName, Type propOrFieldType, MemberInfo mi) { var isEnumerable = propOrFieldType.Namespace != "System" && typeof(IEnumerable).IsAssignableFrom(propOrFieldType); var isArray = propOrFieldType.IsArray; var isGeneric = propOrFieldType.IsGenericType; var underlyingType = propOrFieldType; if (isGeneric || isArray) { underlyingType = isArray ? propOrFieldType.GetElementType() : propOrFieldType.GetGenericArguments()[0]; } if (underlyingType == null) { throw new Exception("Can't detect type."); } var isComplex = underlyingType.Namespace != "System" && !underlyingType.IsPrimitive && !underlyingType.IsValueType; var nullableType = Nullable.GetUnderlyingType(propOrFieldType); string methodName; if (isArray) { methodName = isComplex ? nameof(MappingContext.ConvertArrayComplex) : nameof(MappingContext.ConvertArray); } else if (isEnumerable) { if (propOrFieldType.GetGenericTypeDefinition() == typeof(SortedSet <>)) { methodName = isComplex ? nameof(MappingContext.ConvertSortedSetComplex) : nameof(MappingContext.ConvertSortedSet); } else { methodName = isComplex ? nameof(MappingContext.ConvertListComplex) : nameof(MappingContext.ConvertList); } } else if (nullableType != null) { methodName = isComplex ? nameof(MappingContext.ConvertNullableComplex) : nameof(MappingContext.ConvertNullable); underlyingType = nullableType; } else { methodName = isComplex ? nameof(MappingContext.ConvertComplex) : nameof(MappingContext.Convert); } var convertMethod = typeof(MappingContext).GetMethod( methodName, BindingFlags.Instance | BindingFlags.NonPublic); if (convertMethod == null) { throw new Exception($"Convert method with name \"{methodName}\" does not found."); } Expression defaultValue; if (defaultObject != null) { if (mi is PropertyInfo pi) { defaultValue = Constant( pi.GetValue(defaultObject), propOrFieldType); } else if (mi is FieldInfo fi) { defaultValue = Constant( fi.GetValue(defaultObject), propOrFieldType); } else { defaultValue = PropertyOrField( Constant(defaultObject), propOrFieldName); } } else { defaultValue = Default(propOrFieldType); } var convertMethodGeneric = isArray || isEnumerable || nullableType != null ? convertMethod.MakeGenericMethod(underlyingType) : convertMethod.MakeGenericMethod(propOrFieldType); var convertCall = Call( context, convertMethodGeneric, prefix, Constant(propOrFieldName), first, values, defaultValue); // return Bind(mi, convertCall); return(convertCall, mi); } var converts = props .Select(property => Process(property.Name, property.PropertyType, property)) .ToList(); converts.AddRange(fields .Select(field => Process(field.Name, field.FieldType, field))); var constructorArguments = constructorParams?.Select(x => { var converter = converts.First(c => c.Item2.Name.Equals(x.Name, StringComparison.InvariantCultureIgnoreCase)); converts.Remove(converter); return(converter.Item1); }); NewExpression newValue; if (IsValueType || ConstructorToUse == null || constructorParams == null) { newValue = New(type); } else { newValue = New(ConstructorToUse, constructorArguments); } Expression expr; if (converts.Count > 0) { var bindings = converts .Select(t => (MemberBinding)Bind(t.Item2, t.Item1)); expr = MemberInit(newValue, bindings.ToArray()); } else { expr = newValue; } MapExpression = Lambda <Func <MappingContext, string, List <Items>, Items, T> >( expr, context, prefix, values, first).CompileFast(); }