예제 #1
0
            private bool CanUseDirectAssignment(TypePair pair, PropertyOrFieldInfo destinationMember, PropertyOrFieldInfo sourceMember, Type nullableType, ProposedHierarchicalMapping hierarchicalMapping)
            {
                Type sourceMemberType = null;

                if (sourceMember == null)
                {
                    if (hierarchicalMapping == null)
                    {
                        return(false);
                    }
                }
                else
                {
                    sourceMemberType = sourceMember.PropertyOrFieldType;
                }

                if (hierarchicalMapping != null)
                {
                    sourceMemberType = hierarchicalMapping.ReturnType;
                }

                if (!destinationMember.PropertyOrFieldType.IsAssignableFrom(sourceMemberType))
                {
                    if (sourceMemberType.IsNullableValueType() && destinationMember.PropertyOrFieldType.IsAssignableFrom(nullableType))
                    {
                        return(true);
                    }
                    else if (ConversionTypeHelper.AreConvertible(sourceMemberType, destinationMember.PropertyOrFieldType))
                    {
                        return(true);
                    }
                    else
                    {
                        return(false);
                    }
                }

                if (pair.SourceType == pair.DestinationType && this.options.Conventions.MakeCloneIfDestinationIsTheSameAsSource)
                {
                    if (sourceMemberType.IsValueType || sourceMemberType == typeof(string))
                    {
                        return(true);
                    }
                    else
                    {
                        return(false);
                    }
                }

                // Can't assign enumerable memebers to eachother, we leave that decision to the code
                // generator which can determine if we need to preserve the contents of the enumerable.
                if (CollectionTypeHelper.IsEnumerable(destinationMember.PropertyOrFieldType) &&
                    CollectionTypeHelper.IsEnumerable(sourceMemberType) &&
                    this.options.Conventions.PreserveDestinationListContents) // but only if the option is turned on at all
                {
                    return(false);
                }

                return(true);
            }
예제 #2
0
 public MappingContext(PropertyOrFieldInfo source, PropertyOrFieldInfo dest, int depth, IMemberMapper mapper)
 {
     Source      = source;
     Destination = dest;
     Depth       = depth;
     Mapper      = mapper;
 }
예제 #3
0
        public bool IsMemberIgnored(Type sourceType, PropertyOrFieldInfo destinationProperty)
        {
            if (mapper.Options.Conventions.IgnoreMemberAttributeShouldBeRespected)
            {
                var ignoreAttribute = destinationProperty.GetCustomAttributes(typeof(IgnoreMemberAttribute), false).SingleOrDefault() as IgnoreMemberAttribute;

                if (ignoreAttribute != null)
                {
                    var ignore = true;

                    if (!string.IsNullOrEmpty(ignoreAttribute.Profile))
                    {
                        ignore &= ignoreAttribute.Profile == mapper.Profile;
                    }

                    if (ignoreAttribute.WhenSourceTypeIs != null)
                    {
                        ignore &= ignoreAttribute.WhenSourceTypeIs == sourceType;
                    }

                    if (ignore)
                    {
                        return(true);
                    }
                }
            }
            return(false);
        }
        /// <summary>
        /// Get the OData property name.
        /// </summary>
        /// <param name="methodCallExpression">The expression from which to parse the OData property name.</param>
        /// <param name="useCamlCase">Is the property name expected to be in CAML case?</param>
        /// <returns>the OData property name.</returns>
        public static PropertyOrFieldInfo GetPropertyName(MethodCallExpression methodCallExpression, bool useCamlCase)
        {
            if (methodCallExpression == null)
            {
                throw new ArgumentNullException(nameof(methodCallExpression));
            }

            IList <PropertyOrFieldInfo> tokens = new List <PropertyOrFieldInfo>();
            bool useCamlCaseLocal = useCamlCase;
            int  idx = -1;

            foreach (Expression argumentExpression in methodCallExpression.Arguments)
            {
                idx++;
                switch (argumentExpression.NodeType)
                {
                case ExpressionType.MemberAccess:
                {
                    MemberExpression argumentMemberExpression = argumentExpression as MemberExpression;
                    if (argumentMemberExpression == null)
                    {
                        throw new ArgumentException($"Expected {nameof(methodCallExpression)}.{nameof(MethodCallExpression.Arguments)}[{idx}] to be of type {nameof(MemberExpression)}\r\n\t{methodCallExpression}", nameof(methodCallExpression));
                    }

                    PropertyOrFieldInfo newToken = GetPropertyName(argumentMemberExpression, useCamlCaseLocal);
                    useCamlCaseLocal = useCamlCaseLocal || newToken.UseCamlCase;
                    tokens.Add(newToken);
                }

                break;

                case ExpressionType.Lambda:
                {
                    LambdaExpression argumentLambdaExpression = argumentExpression as LambdaExpression;
                    if (argumentLambdaExpression == null)
                    {
                        throw new ArgumentException($"Expected {nameof(methodCallExpression)}.{nameof(MethodCallExpression.Arguments)}[{idx}] to be of type {nameof(LambdaExpression)}\r\n\t{methodCallExpression}", nameof(methodCallExpression));
                    }

                    PropertyOrFieldInfo newToken = GetPropertyName(argumentLambdaExpression, useCamlCaseLocal);
                    useCamlCaseLocal = useCamlCaseLocal || newToken.UseCamlCase;
                    tokens.Add(newToken);
                }

                break;

                default:
                    throw new ArgumentException($"Invalid expression type {argumentExpression.NodeType}\r\n\t{methodCallExpression}", nameof(methodCallExpression));
                }
            }

            PropertyOrFieldInfo lastPropertyInfo = tokens.LastOrDefault();

            return(new PropertyOrFieldInfo(
                       lastPropertyInfo?.PropertyOrFieldName,
                       string.Join(Constants.ODataMemberAccessOperator, tokens),
                       lastPropertyInfo?.PropertyOrFieldType,
                       useCamlCaseLocal || (lastPropertyInfo?.UseCamlCase ?? false)));
        }
예제 #5
0
        public PropertyOrFieldInfo GetMatchingSourceMember(PropertyOrFieldInfo destinationProperty)
        {
            PropertyOrFieldInfo sourceProperty;

            SourceMembers.TryGetValue(destinationProperty.Name, out sourceProperty);

            return(sourceProperty);
        }
예제 #6
0
        internal static Type TryGetNullableType(PropertyOrFieldInfo sourceMember)
        {
            if (sourceMember == null)
            {
                return(null);
            }

            return(TryGetNullableType(sourceMember.PropertyOrFieldType));
        }
        internal static LambdaExpression Bind(Type sourceType, PropertyOrFieldInfo member, LambdaExpression conversion, LambdaExpression customMapping = null)
        {
            var parameterToReplace = conversion.Parameters.Single();

            var newParameter = Expression.Parameter(sourceType, "p");

            var accessMember = Expression.MakeMemberAccess(newParameter, member);

            var visitor = new ParameterVisitor(parameterToReplace, accessMember);


            var newBody = visitor.Visit(conversion.Body);

            return(Expression.Lambda(newBody, newParameter));
        }
예제 #8
0
            private bool CanAssignSourceItemsToDestination(PropertyOrFieldInfo destinationMember, PropertyOrFieldInfo sourceMember, Type typeOfSourceEnumerable, Type typeOfDestinationEnumerable)
            {
                if (typeOfDestinationEnumerable == typeOfSourceEnumerable)
                {
                    if (typeOfSourceEnumerable.IsPrimitive || typeOfSourceEnumerable == typeof(string))
                    {
                        return(true);
                    }

                    if (sourceMember.DeclaringType == destinationMember.DeclaringType && this.options.Conventions.MakeCloneIfDestinationIsTheSameAsSource)
                    {
                        return(false);
                    }

                    return(true);
                }
                return(false);
            }
예제 #9
0
        public ProposedHierarchicalMapping ProposeHierarchicalMapping(PropertyOrFieldInfo destinationMember)
        {
            var split = CamelCaseHelper.SplitOnCamelCase(destinationMember.Name);

            if (split.Count <= 1)
            {
                return(null);
            }

            var sourceMembers = SourceMembers;

            var memberStack = new List <PropertyOrFieldInfo>();

            var applies = GetMemberOnType(sourceType, split, 0, memberStack);

            if (applies)
            {
                return(new ProposedHierarchicalMapping(memberStack));
            }

            return(null);
        }
        /// <summary>
        /// Get the OData property name.
        /// </summary>
        /// <param name="memberExpression">The expression from which to parse the OData property name.</param>
        /// <param name="useCamlCase">Is the property name expected to be in CAML case?</param>
        /// <returns>the OData property name.</returns>
        public static PropertyOrFieldInfo GetPropertyName(MemberExpression memberExpression, bool useCamlCase)
        {
            if (memberExpression == null)
            {
                throw new ArgumentNullException(nameof(memberExpression));
            }

            PropertyOrFieldInfo parentProperty = null;

            if (memberExpression.Expression != null)
            {
                switch (memberExpression.Expression.NodeType)
                {
                case ExpressionType.MemberAccess:
                {
                    MemberExpression childMemberExpression = memberExpression.Expression as MemberExpression;
                    if (childMemberExpression == null)
                    {
                        throw new ArgumentException($"Expected {nameof(memberExpression)}.{nameof(MemberExpression.Expression)} to be of type {nameof(MemberExpression)}\r\n\t{memberExpression}", nameof(memberExpression));
                    }

                    parentProperty = GetPropertyName(childMemberExpression, false);
                }

                break;

                case ExpressionType.Call:
                {
                    MethodCallExpression methodCallExpression = memberExpression.Expression as MethodCallExpression;
                    if (methodCallExpression == null)
                    {
                        throw new ArgumentException($"Expected {nameof(memberExpression)}.{nameof(MemberExpression.Expression)} to be of type {nameof(MethodCallExpression)}\r\n\t{memberExpression}", nameof(memberExpression));
                    }

                    parentProperty = GetPropertyName(methodCallExpression, false);
                }

                break;

                case ExpressionType.Parameter:
                    break;

                default:
                    throw new ArgumentException($"Invalid expression type {memberExpression.NodeType}\r\n\t{memberExpression}", nameof(memberExpression));
                }
            }

            PropertyOrFieldInfo leafProperty = null;
            PropertyInfo        propertyInfo = memberExpression.Member as PropertyInfo;

            if (propertyInfo != null)
            {
                leafProperty = GetPropertyName(propertyInfo, useCamlCase || (parentProperty?.UseCamlCase ?? false));
            }
            else
            {
                FieldInfo fieldInfo = memberExpression.Member as FieldInfo;
                if (fieldInfo == null)
                {
                    throw new ArgumentException($"Invalid expression body type {memberExpression.Member.GetType()}", nameof(memberExpression));
                }

                leafProperty = GetFieldName(fieldInfo, parentProperty?.UseCamlCase ?? false);
            }

            if (parentProperty == null)
            {
                return(leafProperty);
            }
            else
            {
                return(new PropertyOrFieldInfo(
                           leafProperty.PropertyOrFieldName,
                           string.Concat(
                               parentProperty,
                               Constants.ODataMemberAccessOperator,
                               leafProperty),
                           leafProperty.PropertyOrFieldType,
                           leafProperty.UseCamlCase));
            }
        }
예제 #11
0
        private Node GetDeserializationNode(PropertyOrFieldInfo member)
        {
            Func<PropertyOrFieldInfo, Node> nodeFunc;

              if (!_deserializers.TryGetValue(member.PropertyOrFieldType, out nodeFunc))
              {
            var key = _deserializers.Keys.FirstOrDefault(k => k.IsAssignableFrom(member.PropertyOrFieldType));

            if (key != null)
            {
              nodeFunc = _deserializers[key];
            }
            else
            {
              key = _deserializers.Keys.FirstOrDefault(k => member.PropertyOrFieldType.IsAssignableFrom(k));

              if (key != null)
              {
            nodeFunc = _deserializers[key];
              }

            }

              }

              Node node;

              if (nodeFunc != null)
              {
            node = nodeFunc(member);
              }
              else if (_recursionStack.Contains(member.PropertyOrFieldType))
              {
            node = new RecursionNode
            {
              Type = member.PropertyOrFieldType,
              Member = member
            };
              }
              else
              {
            var customNode = new UnknownTypeNode
            {
              Type = member.PropertyOrFieldType,
              Member = member,
              Children = new List<Node>()
            };

            var members = GetMembers(member.PropertyOrFieldType);

            foreach (var childMember in members)
            {
              var childNode = GetDeserializationNode(childMember);
              customNode.Children.Add(childNode);
            }

            node = customNode;

              }

              return node;
        }
예제 #12
0
 private bool HasNoSourceMember(Expression customExpression, PropertyOrFieldInfo sourceMember)
 {
     return(sourceMember == null &&
            customExpression == null);
 }
예제 #13
0
 public IncompatibleMapping(PropertyOrFieldInfo member, ProposedTypeMapping mapping = null)
 {
     this.mapping = mapping;
     this.member  = member;
 }
예제 #14
0
 public MemberOption(PropertyOrFieldInfo source, PropertyOrFieldInfo destination)
 {
     this.Source      = source;
     this.Destination = destination;
 }
예제 #15
0
 public void Load(PropertyOrFieldInfo reference) => UnderlyingPropertyOrFieldInfo = reference;
예제 #16
0
            private void GenerateEnumerableMapping(int currentDepth, MemberOptions options, CustomMapping customMapping, ProposedTypeMapping typeMapping, PropertyOrFieldInfo destinationMember, PropertyOrFieldInfo sourceMember)
            {
                var typeOfSourceEnumerable      = CollectionTypeHelper.GetTypeInsideEnumerable(sourceMember.PropertyOrFieldType);
                var typeOfDestinationEnumerable = CollectionTypeHelper.GetTypeInsideEnumerable(destinationMember.PropertyOrFieldType);

                var canAssignSourceItemsToDestination = CanAssignSourceItemsToDestination(destinationMember, sourceMember, typeOfSourceEnumerable, typeOfDestinationEnumerable);

                if (canAssignSourceItemsToDestination)
                {
                    typeMapping.ProposedTypeMappings.Add(
                        new ProposedTypeMapping
                    {
                        DestinationMember = destinationMember,
                        SourceMember      = sourceMember,
                        ProposedMappings  = new List <ProposedMemberMapping>()
                    });
                }
                else
                {
                    var complexPair = new TypePair(typeOfSourceEnumerable, typeOfDestinationEnumerable);

                    var complexTypeMapping = GetComplexTypeMapping(currentDepth + 1, complexPair, options, customMapping);

                    if (complexTypeMapping != null)
                    {
                        complexTypeMapping = complexTypeMapping.Clone();

                        complexTypeMapping.DestinationMember = destinationMember;
                        complexTypeMapping.SourceMember      = sourceMember;

                        CustomMapping customMappingForType;

                        TryGetCustomMapping(complexPair, out customMappingForType);

                        complexTypeMapping.CustomMapping = customMappingForType;

                        typeMapping.ProposedTypeMappings.Add(complexTypeMapping);
                    }
                    else
                    {
                        typeMapping.DoNotCache = true;
                    }
                }
            }
예제 #17
0
            /// <summary>
            /// Go one deeper into the type hierarchy to map between a source and destination member.
            /// </summary>
            private void GenerateComplexTypeMapping(int currentDepth, MemberOptions options, CustomMapping customMapping, ProposedTypeMapping typeMapping, PropertyOrFieldInfo destinationMember, PropertyOrFieldInfo sourceMember)
            {
                var complexPair = new TypePair(sourceMember.PropertyOrFieldType, destinationMember.PropertyOrFieldType);

                // Go one deeper
                var complexTypeMapping = GetComplexTypeMapping(currentDepth + 1, complexPair, options, customMapping);

                // If a mapping has been found
                if (complexTypeMapping != null)
                {
                    complexTypeMapping = complexTypeMapping.Clone();

                    complexTypeMapping.DestinationMember = destinationMember;
                    complexTypeMapping.SourceMember      = sourceMember;

                    CustomMapping customMappingForType;

                    TryGetCustomMapping(complexPair, out customMappingForType);

                    complexTypeMapping.CustomMapping = customMappingForType;

                    typeMapping.ProposedTypeMappings.Add(complexTypeMapping);
                }
                else
                {
                    // If no mapping has been found, don't cache the 'owning' typemapping as it will cause issues later
                    typeMapping.DoNotCache = true;
                }
            }
예제 #18
0
 private static bool AreMembersIEnumerable(PropertyOrFieldInfo destinationMember, PropertyOrFieldInfo sourceMember)
 {
     return(CollectionTypeHelper.IsEnumerable(sourceMember.PropertyOrFieldType) &&
            CollectionTypeHelper.IsEnumerable(destinationMember.PropertyOrFieldType));
 }
예제 #19
0
 public void MapProperty(PropertyOrFieldInfo source, PropertyOrFieldInfo destination)
 {
     this.Source      = source;
     this.Destination = destination;
 }
예제 #20
0
        private bool GetMemberOnType(Type type, IList <string> members, int index, IList <PropertyOrFieldInfo> memberStack)
        {
            var name = members[index];

            var member = type.GetMember(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy).FirstOrDefault();

            if (member == null)
            {
                // We couldn't find a property with that name, so in case that there's another property in the list after this one
                // try appending that and see if that results in a valid member.
                // Example: User.FirstName won't match to a property UserFirstName here, because it will have split it to 'User', 'First' and 'Name'.
                // This extra check will make sure it also tries to find a property 'First' + 'Name' on the source type before giving up.
                // TODO: Expand this to allow a property to consist of more than two 'camelcased' parts.
                index++;

                var memberName = name;

                while (index < members.Count)
                {
                    memberName += members[index];

                    member = type.GetMember(memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy).FirstOrDefault();

                    index++;

                    if (member != null)
                    {
                        break;
                    }
                }

                if (index < members.Count)
                {
                    memberStack.Add(member);

                    return(GetMemberOnType(((PropertyOrFieldInfo)member).PropertyOrFieldType, members, index, memberStack));
                }

                if (member == null)
                {
                    return(false);
                }
            }

            if (!PropertyOrFieldInfo.IsPropertyOrField(member))
            {
                return(false);
            }

            if (member.MemberType == MemberTypes.Property)
            {
                var property = (PropertyInfo)member;

                if (!property.CanRead)
                {
                    return(false);
                }
            }

            memberStack.Add(member);

            if (index < members.Count - 1)
            {
                return(GetMemberOnType(((PropertyOrFieldInfo)member).PropertyOrFieldType, members, index + 1, memberStack));
            }

            return(true);
        }