Пример #1
0
        internal static bool AreConvertible(Type source, Type destination)
        {
            var nullableSource = NullableTypeHelper.TryGetNullableType(source);

            source = nullableSource ?? source;

            var nullableDestination = NullableTypeHelper.TryGetNullableType(destination);

            destination = nullableDestination ?? destination;

            return(AreExplicitlyConvertible(source, destination) ||
                   AreImplicitlyConvertible(source, destination) ||
                   CanConvertToOrFromEnum(source, destination));
        }
Пример #2
0
            /// <summary>
            /// Returns a type mapping of the TypePair you pass in.
            /// </summary>
            /// <returns></returns>
            private ProposedTypeMapping GetTypeMapping(int currentDepth, TypePair pair, MemberOptions options = null, CustomMapping customMapping = null)
            {
                if (!typeStack.Contains(pair))
                {
                    typeStack.Push(pair);
                }
                else if (this.options.Safety.IfRecursiveRelationshipIsDetected == RecursivePropertyOptions.ThrowIfRecursionIsDetected)
                {
                    // Oh noes, recursion!
                    throw new RecursiveRelationshipException(pair);
                }
                // if it's a recursive relationship, by default we return null which is handled after the method returns
                else
                {
                    return(null);
                }

                var typeMapping = new ProposedTypeMapping();

                typeMapping.SourceMember      = null;
                typeMapping.DestinationMember = null;

                Type destinationType, sourceType;

                // If it's an enumerable type (List<>, IEnumerable<>, etc) then we're currently interested
                // in the type 'inside' the enumerable.
                if (CollectionTypeHelper.IsEnumerable(pair.DestinationType))
                {
                    destinationType = CollectionTypeHelper.GetTypeInsideEnumerable(pair.DestinationType);
                }
                else
                {
                    destinationType = pair.DestinationType;
                }

                // Same here.
                if (CollectionTypeHelper.IsEnumerable(pair.SourceType))
                {
                    sourceType = CollectionTypeHelper.GetTypeInsideEnumerable(pair.SourceType);
                }
                else
                {
                    sourceType = pair.SourceType;
                }

                // The memberprovider is responsible for linking a destination member with a source member
                var memberProvider = this.strategy.MemberProviderFactory.GetMemberProvider(sourceType, destinationType, mapper);

                // Loop through all members it could find
                foreach (var mapping in GetTypeMembers(memberProvider, options, currentDepth))
                {
                    var destinationMember = mapping.Destination;
                    var sourceMember      = mapping.Source;

                    // Does the memberprovider see any reason to ignore this member?
                    if (memberProvider.IsMemberIgnored(sourceType, destinationMember))
                    {
                        continue;
                    }


                    Expression customExpression = null;

                    // Try to extract an expression that was supplied for this destination member
                    if (customMapping != null)
                    {
                        customExpression = customMapping.GetExpressionForMember(destinationMember);

                        if (mapping.ConversionFunction == null)
                        {
                            var conversionFunction = customMapping.GetConversionFunction(sourceMember, destinationMember);

                            mapping.ConversionFunction = conversionFunction;
                        }
                    }


                    // Did the user supply a function to transform the source member's value?
                    if (mapping.ConversionFunction != null)
                    {
                        // If no custom mapping yet, then we need to create one
                        // as it's where we'll be storing the conversion function
                        if (customMapping == null)
                        {
                            customMapping = new CustomMapping
                            {
                                DestinationType = destinationType
                            };

                            customMappingCache.AddOrUpdate(pair, customMapping, (k, v) => customMapping);

                            typeMapping.CustomMapping = customMapping;
                        }

                        // Let the custom mapping be the owner of the conversion function
                        customMapping.AddConversionFunction(sourceMember, destinationMember, mapping.ConversionFunction);
                    }
                    else if (customMapping != null)
                    {
                    }

                    ProposedHierarchicalMapping hierarchicalMapping = null;

                    // No source member or can't write to the destination?
                    if (HasNoSourceMember(customExpression, sourceMember) || !destinationMember.CanWrite)
                    {
                        if (this.options.Conventions.AutomaticallyFlattenHierarchies)
                        {
                            // Propose a mapping that flattens a hierarchy if possible.
                            // For example, map type.CompanyName to otherType.Company.Name
                            hierarchicalMapping = memberProvider.ProposeHierarchicalMapping(destinationMember);
                        }

                        // No way to map this thing? Add it to incompatible members if the option has been turned on.
                        // Will cause an (intended) exception later on, allowing you to verify your mappings
                        // for correctness and completeness.
                        if (hierarchicalMapping == null && this.options.Strictness.ThrowWithoutCorrespondingSourceMember)
                        {
                            typeMapping.IncompatibleMappings.Add(destinationMember);
                        }
                    }

                    // Nullable value types screw up everything!
                    var nullableType = NullableTypeHelper.TryGetNullableType(sourceMember);

                    // Can we do a simple right to left assignment between the members?
                    // So, are they basically the same type or do we need to do further mapping?
                    var canUseSimpleTypeMapping = CanUseDirectAssignment(pair, destinationMember, sourceMember, nullableType, hierarchicalMapping);

                    if (canUseSimpleTypeMapping)
                    {
                        // If simple mapping is possible create a mapping between the members
                        typeMapping.ProposedMappings.Add
                        (
                            new ProposedMemberMapping
                        {
                            SourceMember        = sourceMember,
                            DestinationMember   = destinationMember,
                            HierarchicalMapping = hierarchicalMapping
                        }
                        );
                    }
                    // No simple assignment, but a custom expression is supplied
                    // and that's just as good as having a direct assignment mapping
                    else if (customExpression != null || mapping.ConversionFunction != null)
                    {
                        typeMapping.ProposedMappings.Add
                        (
                            new ProposedMemberMapping
                        {
                            SourceMember        = sourceMember,
                            DestinationMember   = destinationMember,
                            HierarchicalMapping = hierarchicalMapping
                        }
                        );
                    }
                    // We have a source member but can't directly assign the source to the destination.
                    // Further mapping is needed.
                    else if (sourceMember != null)
                    {
                        // Is the member of an IEnumerable type?
                        if (AreMembersIEnumerable(destinationMember, sourceMember))
                        {
                            // Create a deeper mapping for IEnumerable members
                            GenerateEnumerableMapping(currentDepth, options, customMapping, typeMapping, destinationMember, sourceMember);
                        }
                        else
                        {
                            // Create a deeper mapping for a 'regular' type.
                            GenerateComplexTypeMapping(currentDepth, options, customMapping, typeMapping, destinationMember, sourceMember);
                        }
                    }
                    // All we have is a destination member and a custom expression
                    // that gives the destination member a value. Good enough!
                    else if (customExpression != null)
                    {
                        typeMapping.ProposedMappings.Add
                        (
                            new ProposedMemberMapping
                        {
                            SourceMember      = null,
                            DestinationMember = destinationMember
                        }
                        );
                    }
                }

                // Don't cache the typemapping when this flag has been set.
                // That happens when the maximum depth was reached during the mapping
                // for this particular type and we didn't explore the full depth
                // of the type. We don't wanna reuse this typemapping at a later time
                // because the mapping might be for something completely different
                // at a depth at which the full depth CAN be explored.
                if (!typeMapping.DoNotCache)
                {
                    mappingCache[pair] = typeMapping;
                }

                typeStack.Pop();

                return(typeMapping);
            }