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); }
public MappingContext(PropertyOrFieldInfo source, PropertyOrFieldInfo dest, int depth, IMemberMapper mapper) { Source = source; Destination = dest; Depth = depth; Mapper = mapper; }
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))); }
public PropertyOrFieldInfo GetMatchingSourceMember(PropertyOrFieldInfo destinationProperty) { PropertyOrFieldInfo sourceProperty; SourceMembers.TryGetValue(destinationProperty.Name, out sourceProperty); return(sourceProperty); }
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)); }
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); }
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)); } }
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; }
private bool HasNoSourceMember(Expression customExpression, PropertyOrFieldInfo sourceMember) { return(sourceMember == null && customExpression == null); }
public IncompatibleMapping(PropertyOrFieldInfo member, ProposedTypeMapping mapping = null) { this.mapping = mapping; this.member = member; }
public MemberOption(PropertyOrFieldInfo source, PropertyOrFieldInfo destination) { this.Source = source; this.Destination = destination; }
public void Load(PropertyOrFieldInfo reference) => UnderlyingPropertyOrFieldInfo = reference;
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; } } }
/// <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; } }
private static bool AreMembersIEnumerable(PropertyOrFieldInfo destinationMember, PropertyOrFieldInfo sourceMember) { return(CollectionTypeHelper.IsEnumerable(sourceMember.PropertyOrFieldType) && CollectionTypeHelper.IsEnumerable(destinationMember.PropertyOrFieldType)); }
public void MapProperty(PropertyOrFieldInfo source, PropertyOrFieldInfo destination) { this.Source = source; this.Destination = destination; }
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); }