コード例 #1
0
        /// <summary>
        /// Checks if the specified <paramref name="maybeCollectionTarget"/> parameter
        /// is an object which is not null and which supports any collection element adding
        /// facility. The specified <paramref name="value"/> will then be assigned to the
        /// collection.
        /// </summary>
        /// <remarks>
        /// <para>
        /// This method will be needed in two cases:
        /// <list type="number">
        /// <item>A property should be assigned, which has a collection-like type. These properties
        /// won't be assigned directly but they are expected to have a not-null collection value.
        /// Adding children to them will cause calling some "Add" method on the existing instance.</item>
        /// <item>Child elements should be assigned to an object which doesn't support
        /// the <see cref="IContentEnabled"/> interface. So if there is no content property,
        /// the parser tries to add children directly to the object, if it is supported.</item>
        /// </list>
        /// In both cases, there is already an existing (collection-like) instance, to that the
        /// specified <paramref name="value"/> should be assigned, so this method has no
        /// need to create the collection itself.
        /// </para>
        /// <para>
        /// If this method cannot handle the specified target object
        /// <paramref name="maybeCollectionTarget"/>, or if this parameter is <c>null</c>,
        /// it will return <c>false</c> to signal that it couldn't do the assignment.
        /// </para>
        /// </remarks>
        /// <param name="maybeCollectionTarget">Parameter holding an instance which may be
        /// a collection type to add the <paramref name="value"/> to. May also be <c>null</c>,
        /// which will result in a return value of <c>false</c>.</param>
        /// <param name="value">The value to assign to the target object. If the value has
        /// a collection type compatible with the <paramref name="maybeCollectionTarget"/> target,
        /// the contents will be transferred to the target object, else this parameter value
        /// will be added to the target itself.</param>
        /// <returns><c>true</c>, if the method could handle the assignment, else <c>false</c>.</returns>
        public static bool CheckHandleCollectionAssignment(object maybeCollectionTarget, object value)
        {
            if (maybeCollectionTarget == null || value == null)
            {
                return(false);
            }
            Type targetType = maybeCollectionTarget.GetType();
            // Check for List
            Type       resultType;
            Type       entryType;
            MethodInfo method;

            FindImplementedListType(targetType, out resultType, out entryType);
            if (resultType != null)
            {
                method = entryType == null?targetType.GetMethod("Add") : targetType.GetMethod("Add", new Type[] { entryType });

                // Have to cast to ICollection, because the type converter cannot cope with the situation corretcly if we cast to IEnumerable
                ICollection col = (ICollection)TypeConverter.Convert(value, typeof(ICollection));
                if (col == null)
                {
                    // The type converter converts null to null rather than to an empty collection, so we have to handle this case explicitly
                    method.Invoke(maybeCollectionTarget, new object[] { null });
                }
                else
                {
                    foreach (object child in col)
                    {
                        method.Invoke(maybeCollectionTarget, new object[] { child });
                    }
                }
                return(true);
            }
            // Check for Dictionary
            Type keyType;
            Type valueType;

            FindImplementedDictionaryType(targetType, out resultType, out keyType, out valueType);
            Type sourceDictType;
            Type sourceKeyType;
            Type sourceValueType;

            FindImplementedDictionaryType(value.GetType(), out sourceDictType, out sourceKeyType, out sourceValueType);
            if (resultType != null && sourceDictType != null)
            {
                PropertyInfo targetItemProperty = keyType == null?targetType.GetProperty("Item") : targetType.GetProperty("Item", new Type[] { keyType });

                MethodInfo targetItemSetter = targetItemProperty.GetSetMethod();
                foreach (KeyValuePair <object, object> kvp in (IEnumerable)value)
                {
                    targetItemSetter.Invoke(maybeCollectionTarget, new object[] { kvp.Key, kvp.Value });
                }
                return(true);
            }
            // Check for IAddChild
            if (IsIAddChild(maybeCollectionTarget.GetType(), out method, out entryType))
            {
                foreach (object child in (ICollection)TypeConverter.Convert(value, typeof(ICollection)))
                {
                    method.Invoke(maybeCollectionTarget, new object[] { TypeConverter.Convert(child, entryType) });
                }
                return(true);
            }
            return(false);
        }