Пример #1
0
        protected override void OnApply(object target, MappingContext context)
        {
            // .......................................
            // Process inherited read commands only
            foreach (ReadCommand read in this.InheritedReads.Values)
            {
                if (this.ReadCommands.Contains(read))
                {
                    continue;
                }

                read.Read(context);
            }

            // .......................................
            // Check condition - only external read commands are available here

            if (this.Condition != null)
            {
                var condition = (bool)this.Condition.GetOuput(context, inheritedOnly: true);
                if (!condition)
                {
                    return;
                }
            }

            // .......................................
            // Process inner read commands only
            foreach (ReadCommand read in this.ReadCommands)
            {
                read.Read(context);
            }

            // .......................................
            // Apply mapping operation

            object nextTarget = target;

            // Check condition


            if (this.TargetMember != null)
            {
                PropertyInfo property = this.TargetMember is PropertyInfo ? (PropertyInfo)this.TargetMember : null;
                FieldInfo    field    = this.TargetMember is FieldInfo ? (FieldInfo)this.TargetMember : null;

                // .......................................
                // Get the command output

                object output = null;
                if (this.Value != null)
                {
                    try { output = this.Value.GetOutput(context); }
                    catch (Exception ex)
                    {
                        if (this.IsRequired)
                        {
                            throw new MappingException(String.Format("Failed to get the output of the map command for {0}.{1}. See inner exception for details.", this.TargetType.Name, this.TargetMember.Name), ex);
                        }
                        else
                        {
                            Log.Write(String.Format("Failed to get the output of the map command for {0}.{1}.", this.TargetType.Name, this.TargetMember.Name), ex);
                            return;
                        }
                    }
                }

                // .......................................
                // Get final value

                object value = null;
                if (output != null && !this.ValueType.IsAssignableFrom(output.GetType()))
                {
                    // Try a converter when incompatible types are detected
                    TypeConverter converter = TypeDescriptor.GetConverter(this.ValueType);
                    if (converter != null && converter.CanConvertFrom(output.GetType()))
                    {
                        try { value = converter.ConvertFrom(output); }
                        catch (Exception ex)
                        {
                            throw new MappingException(String.Format("Error while converting, '{0}' to {1} for applying to {2}.{3}, using TypeConverter.", output, this.ValueType, this.TargetType.Name, this.TargetMember.Name), ex);
                        }
                    }
                    else                     // no type converter available
                    {
                        // Make C# 4.0 do all the implicit/explicit conversion work at runtime
                        // social.msdn.microsoft.com/Forums/en-US/csharplanguage/thread/fe14d396-bc35-4f98-851d-ce3c8663cd79/

                        MethodInfo dynamicCastMethod = CastGenericMethod.MakeGenericMethod(this.ValueType);
                        try { value = dynamicCastMethod.Invoke(null, new object[] { output }); }
                        catch (Exception ex)
                        {
                            throw new MappingException(String.Format("Error while converting, '{0}' to {1} for applying to {2}.{3}. using dynamic cast.", output, this.ValueType, this.TargetType.Name, this.TargetMember.Name), ex);
                        }
                    }
                }
                else
                {
                    // Try to create a new
                    if (output == null && this.Value == null)
                    {
                        // Try to create an instance of the value type, since nothing was specified
                        try { output = Activator.CreateInstance(this.ValueType); }
                        catch (Exception ex)
                        {
                            throw new MappingException(String.Format("Cannot create a new instance of {0} for applying to {2}.{3}. (Did you forget the 'Value' attribute?)", this.ValueType, this.TargetType.Name, this.TargetMember.Name), ex);
                        }
                    }

                    // Types might be compatible, just try to assign it
                    value = output;
                }

                // .......................................
                // Check for indexers

                if (Object.Equals(this.Indexer, MapCommand.ListAddingMode))
                {
                    IList list;
                    try
                    {
                        // Try to get the list
                        list = property != null ?
                               (IList)property.GetValue(target, null) :
                               (IList)field.GetValue(target);
                    }
                    catch (InvalidCastException ex)
                    {
                        throw new MappingException(String.Format("{0}.{1} is not an IList and cannot be set with the \"[]\" notation.", this.TargetType.Name, this.TargetMember.Name), ex);
                    }
                    catch (Exception ex)
                    {
                        throw new MappingException(String.Format("Error while mapping to {0}.{1}. See inner exception for details.", this.TargetType.Name, this.TargetMember.Name), ex);
                    }

                    if (list == null)
                    {
                        // List is empty, create a new list
                        Type listType = property != null ? property.PropertyType : field.FieldType;
                        try { list = (IList)Activator.CreateInstance(listType); }
                        catch (Exception ex)
                        {
                            throw new MappingException(String.Format("Cannot create a new list of type {0} for applying to {2}.{3}. To avoid this error, make sure the list is not null before applying the mapping.", listType, this.TargetType.Name, this.TargetMember.Name), ex);
                        }
                    }

                    if (property != null)
                    {
                        property.SetValue(target, list, null);
                    }
                    else
                    {
                        field.SetValue(target, list);
                    }

                    // Add to end of list
                    list.Add(value);
                }
                else if (this.IndexerType != null)
                {
                    // Actual indexer
                    object indexer = null;
                    if (this.Indexer is EvalComponent)
                    {
                        indexer = ((EvalComponent)this.Indexer).GetOuput(context, inheritedOnly: true);
                    }
                    else
                    {
                        indexer = this.Indexer;
                    }

                    Type   collectionType = property != null ? property.PropertyType : field.FieldType;
                    object collection;

                    // Try to get the object with the indexer
                    collection = property != null?
                                 property.GetValue(target, null) :
                                     field.GetValue(target);

                    if (collection == null)
                    {
                        try { collection = Activator.CreateInstance(collectionType); }
                        catch (Exception ex)
                        {
                            throw new MappingException(String.Format("Cannot create a new object of type {0} for applying to {2}.{3}. To avoid this error, make sure the property is not null before applying the mapping.", collectionType, this.TargetType.Name, this.TargetMember.Name), ex);
                        }

                        if (property != null)
                        {
                            property.SetValue(target, collection, null);
                        }
                        else
                        {
                            field.SetValue(target, collection);
                        }
                    }

                    PropertyInfo itemProp = collectionType.GetProperty("Item");
                    itemProp.SetValue(collection, value, new object[] { indexer });
                }
                else
                {
                    // .......................................
                    // Apply to target member

                    try
                    {
                        if (property != null)
                        {
                            // Apply to the property
                            property.SetValue(target, value, null);
                        }
                        else if (field != null)
                        {
                            // Apply to the field
                            field.SetValue(target, value);
                        }
                    }
                    catch (Exception ex)
                    {
                        throw new MappingException(String.Format("Failed to map '{0}' to {1}.{2}. See inner exception for details.", value, this.TargetType.Name, this.TargetMember.Name), ex);
                    }
                }

                nextTarget = value;
            }


            // .......................................
            // Trickle down

            base.OnApply(nextTarget, context);
        }
        internal void Read(MappingContext context)
        {
            // Read from source if necessary
            object rawValue;

            if (!context.FieldValues.TryGetValue(this.Field, out rawValue))
            {
                if (context.Root.OnFieldRequired == null)
                {
                    throw new MappingException("MappingConfiguration.OnFieldRequired is not set - you must supply a function that will return the required field value.");
                }

                try { rawValue = context.Root.OnFieldRequired(this.Field); }
                catch (Exception ex)
                {
                    if (this.IsRequired)
                    {
                        throw new MappingException(String.Format("Failed to read field '{0}'. See inner exception for details.", this.Field), ex);
                    }
                    else
                    {
                        Log.Write(ToString(), String.Format("Failed to read field '{0}'.", Field), ex);
                        return;
                    }
                }
                context.FieldValues.Add(this.Field, rawValue);
            }

            ReadResult result;

            if (!context.ReadResults.TryGetValue(this, out result))
            {
                // Process regular expressions
                result = new ReadResult()
                {
                    FieldValue = rawValue == null ? null : rawValue.ToString()
                };
                bool add = true;

                if (_regex != null && rawValue != null)
                {
                    Match m = _regex.Match(result.FieldValue);
                    if (m.Success)
                    {
                        foreach (string fragment in this.RegexFragments)
                        {
                            Group g = m.Groups[fragment];
                            if (g.Success)
                            {
                                ((dynamic)result)[fragment] = g.Value;
                            }
                        }
                    }
                    else
                    {
                        add = false;
                    }
                }

                if (add)
                {
                    context.ReadResults.Add(this, result);
                }
            }
        }