示例#1
0
        public virtual void SetValue(object targetResource, string propertyName, object propertyValue)
        {
            ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource");
            ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName");
            UpdatableToken token = UpdatableToken.AssertIsToken(targetResource, "targetResource");

            targetResource = token.Resource;
            token.PendingPropertyUpdates[propertyName] = propertyValue;
            this.pendingChanges.Add(delegate {
                object generatedValue;
                Type t          = targetResource.GetType();
                PropertyInfo pi = t.GetProperty(propertyName);
                ExceptionUtilities.CheckObjectNotNull(pi, "Unable to find property '{0}' on type '{1}'", new object[] { propertyName, targetResource.GetType().Name });
                if (this.TryGetStoreGeneratedValue(GetResourceTypeFullName(t), propertyName, out generatedValue))
                {
                    propertyValue = generatedValue;
                }
                if (this.IsCollectionProperty(pi))
                {
                    ExceptionUtilities.CheckObjectNotNull(propertyValue, "Collection property value was null", new object[0]);
                    IEnumerable enumerable = propertyValue as IEnumerable;
                    ExceptionUtilities.CheckObjectNotNull(enumerable, "Collection property value was not an enumerable", new object[0]);
                    this.SetCollectionPropertyValue(targetResource, pi, enumerable);
                }
                else
                {
                    propertyValue = UpdatableToken.ResolveIfToken(propertyValue);
                    pi.SetValue(targetResource, propertyValue, null);
                }
            });
        }
示例#2
0
        /// <summary>
        /// Resets the value of the given resource to its default value
        /// </summary>
        /// <param name="resource">resource whose value needs to be reset</param>
        /// <returns>same resource with its value reset</returns>
        public virtual object ResetResource(object resource)
        {
            ExceptionUtilities.CheckArgumentNotNull(resource, "resource");
            var token = UpdatableToken.AssertIsToken(resource, "resource");

            resource = token.Resource;

            // create a new token to return
            token = new UpdatableToken(resource);

            object newInstance = Activator.CreateInstance(resource.GetType());

            ExceptionUtilities.CheckObjectNotNull(newInstance, "Cannot reset resource because unable to creating new instance of type '{0}' returns null", resource.GetType().Name);

            string[] propertiesToReset = this.ReflectionMetadataHelper.GetPropertiesToReset(GetResourceTypeFullName(resource.GetType()));

            // We must only reset values of scalar, scalar Collection, complex, and complexCollection properties, the key and navigations must stay the same
            foreach (string propertyToReset in propertiesToReset)
            {
                PropertyInfo pi = newInstance.GetType().GetProperty(propertyToReset);
                ExceptionUtilities.CheckObjectNotNull(pi, "Cannot reset resource because unable to find property '{0}'", propertyToReset);
                object newValue = pi.GetValue(newInstance, null);
                this.pendingChanges.Add(() => pi.SetValue(resource, newValue, null));
                token.PendingPropertyUpdates[propertyToReset] = newValue;
            }

            return(token);
        }
示例#3
0
        /// <summary>
        /// Gets the value of the given property on the target object
        /// </summary>
        /// <param name="targetResource">target object which defines the property</param>
        /// <param name="propertyName">name of the property whose value needs to be updated</param>
        /// <returns>the value of the property for the given target resource</returns>
        public virtual object GetValue(object targetResource, string propertyName)
        {
            ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource");
            ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName");

            // resolve the token, and return a pending value if there is one
            // NOTE: this code is specifically to handle cases of mapped complex-type values, because the product does not cache the
            // value returned by CreateResource so we need to take into account any pending updates, or we risk returning stale data
            var token = UpdatableToken.AssertIsToken(targetResource, "targetResource");

            if (token.PendingPropertyUpdates.ContainsKey(propertyName))
            {
                return(token.PendingPropertyUpdates[propertyName]);
            }

            targetResource = token.Resource;
            PropertyInfo pi = targetResource.GetType().GetProperty(propertyName);

            ExceptionUtilities.CheckObjectNotNull(pi, "Cannot find the property '{0}' on type '{1}'", propertyName, targetResource.GetType().Name);

            var value = pi.GetValue(targetResource, null);

            // NOTE: we need to token-ize any complex values before returning them
            // we should have a better way of telling a type is complex, but this works for now
            if (value != null && pi.PropertyType.Assembly == this.GetType().Assembly)
            {
                ExceptionUtilities.Assert(!this.ReflectionMetadataHelper.IsTypeAnEntityType(pi.PropertyType), "GetValue should never be called for reference properties. Type was '{0}', property was '{1}'", pi.PropertyType.FullName, propertyName);
                value = new UpdatableToken(value);
            }

            return(value);
        }
示例#4
0
        private UpdatableToken InstantiateResourceType(string fullTypeName)
        {
            Type           t        = this.MetadataHelper.FindClrTypeByFullName(fullTypeName);
            object         instance = Activator.CreateInstance(t);
            UpdatableToken token    = new UpdatableToken(instance);

            foreach (PropertyInfo p in t.GetProperties())
            {
                object       generatedValue;
                PropertyInfo property = p;
                if (this.IsCollectionProperty(property))
                {
                    Type collectionType = this.GetCollectionPropertyType(GetResourceTypeFullName(t), property.Name);
                    if (collectionType != null)
                    {
                        object newCollection = Activator.CreateInstance(collectionType);
                        token.PendingPropertyUpdates[property.Name] = newCollection;
                        this.pendingChanges.Add(delegate {
                            property.SetValue(instance, newCollection, null);
                        });
                    }
                }
                if (this.TryGetStoreGeneratedValue(fullTypeName, property.Name, out generatedValue))
                {
                    token.PendingPropertyUpdates[property.Name] = generatedValue;
                    this.pendingChanges.Add(delegate {
                        property.SetValue(instance, generatedValue, null);
                    });
                }
            }
            return(token);
        }
示例#5
0
        /// <summary>
        /// Adds the given value to the collection
        /// </summary>
        /// <param name="targetResource">target object which defines the property</param>
        /// <param name="propertyName">name of the property whose value needs to be updated</param>
        /// <param name="resourceToBeAdded">value of the property which needs to be added</param>
        public virtual void AddReferenceToCollection(object targetResource, string propertyName, object resourceToBeAdded)
        {
            ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource");
            ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName");
            ExceptionUtilities.CheckArgumentNotNull(resourceToBeAdded, "resourceToBeAdded");

            // resolve the target token
            var targetToken = UpdatableToken.AssertIsToken(targetResource, "targetResource");

            targetResource = targetToken.Resource;

            // resolve the added token
            resourceToBeAdded = UpdatableToken.AssertIsTokenAndResolve(resourceToBeAdded, "resourceToBeAdded");

            // All resource set reference properties must be of type IList<T> where T is the type of an entitySet
            // Note that we don't support bi-directional relationships so we only handle the one resource set reference property in isolation.
            IList list = this.GetValue(targetToken, propertyName) as IList;

            ExceptionUtilities.CheckObjectNotNull(list, "Property '{0}' on type '{1}' was not a list", propertyName, targetResource.GetType().Name);

            this.pendingChanges.Add(() =>
            {
                list.Add(resourceToBeAdded);
            });
        }
示例#6
0
            public static UpdatableToken AssertIsToken(object resource, string name)
            {
                ExceptionUtilities.CheckArgumentNotNull(resource, "resource");
                UpdatableToken token = resource as UpdatableToken;

                ExceptionUtilities.CheckObjectNotNull(token, "{0} was not a token. Type was: '{1}'", new object[] { name, resource.GetType() });
                return(token);
            }
示例#7
0
            public static object ResolveIfToken(object resource)
            {
                UpdatableToken token = resource as UpdatableToken;

                if (token != null)
                {
                    resource = token.Resource;
                }
                return(resource);
            }
示例#8
0
 public virtual void SetReference(object targetResource, string propertyName, object propertyValue)
 {
     ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource");
     ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName");
     if (propertyValue != null)
     {
         UpdatableToken.AssertIsToken(propertyValue, "propertyValue");
     }
     this.SetValue(targetResource, propertyName, propertyValue);
 }
示例#9
0
 public virtual void SetConcurrencyValues(object resourceCookie, bool?checkForEquality, IEnumerable <KeyValuePair <string, object> > concurrencyValues)
 {
     ExceptionUtilities.CheckArgumentNotNull(resourceCookie, "resourceCookie");
     ExceptionUtilities.ThrowDataServiceExceptionIfFalse(checkForEquality.HasValue, 0x1a1, "Missing concurrency token for update operation", new object[0]);
     ExceptionUtilities.Assert(checkForEquality.Value, "Should not be called with check for equality parameter equal to false", new object[0]);
     ExceptionUtilities.CheckArgumentNotNull(concurrencyValues, "concurrencyValues");
     if (concurrencyValues.Any <KeyValuePair <string, object> >())
     {
         resourceCookie = UpdatableToken.AssertIsTokenAndResolve(resourceCookie, "resourceCookie");
         ExceptionUtilities.ThrowDataServiceExceptionIfFalse(CompareETagValues(this.GetConcurrencyValues(resourceCookie), concurrencyValues), 0x19c, "Concurrency tokens do not match", new object[0]);
     }
 }
示例#10
0
        public virtual object CreateResource(string containerName, string fullTypeName)
        {
            ExceptionUtilities.CheckArgumentNotNull(fullTypeName, "fullTypeName");
            UpdatableToken token = this.InstantiateResourceType(fullTypeName);

            if (containerName != null)
            {
                this.pendingChanges.Add(delegate {
                    this.GetResourceSetEntities(containerName).Add(token.Resource);
                });
            }
            return(token);
        }
示例#11
0
        protected virtual void SetCollectionPropertyValue(object targetResource, PropertyInfo propertyInfo, IEnumerable propertyValue)
        {
            object collection;

            ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource");
            ExceptionUtilities.CheckArgumentNotNull(propertyInfo, "propertyInfo");
            ExceptionUtilities.CheckArgumentNotNull(propertyValue, "propertyValue");
            Type collectionType = this.GetCollectionPropertyType(GetResourceTypeFullName(propertyInfo.ReflectedType), propertyInfo.Name);

            ExceptionUtilities.CheckObjectNotNull(collectionType, "Could not infer collection type for property", new object[0]);
            propertyValue = propertyValue.Cast <object>().Select <object, object>(delegate(object o) {
                return(UpdatableToken.ResolveIfToken(o));
            });
            ConstructorInfo enumerableConstructor = collectionType.GetConstructor(new Type[] { typeof(IEnumerable) });

            if (enumerableConstructor != null)
            {
                collection = enumerableConstructor.Invoke(new object[] { propertyValue });
            }
            else if (collectionType.IsGenericType && (collectionType.GetGenericArguments().Count <Type>() == 1))
            {
                Type            typeArgument = collectionType.GetGenericArguments().Single <Type>();
                ConstructorInfo typedEnumerableConstructor = collectionType.GetConstructor(new Type[] { typeof(IEnumerable <>).MakeGenericType(new Type[] { typeArgument }) });
                if (typedEnumerableConstructor != null)
                {
                    object typedEnumerable = typeof(Enumerable).GetMethod("Cast").MakeGenericMethod(new Type[] { typeArgument }).Invoke(null, new object[] { propertyValue });
                    collection = typedEnumerableConstructor.Invoke(new object[] { typedEnumerable });
                }
                else
                {
                    MethodInfo typedAddMethod = collectionType.GetMethod("Add", new Type[] { typeArgument });
                    ExceptionUtilities.CheckObjectNotNull(typedAddMethod, "Could not find constructor or add method for type: " + collectionType.FullName, new object[0]);
                    collection = Activator.CreateInstance(collectionType);
                    foreach (object element in propertyValue)
                    {
                        typedAddMethod.Invoke(collection, new object[] { element });
                    }
                }
            }
            else
            {
                MethodInfo addMethod = collectionType.GetMethod("Add");
                ExceptionUtilities.CheckObjectNotNull(addMethod, "Could not find constructor or add method for type: " + collectionType.FullName, new object[0]);
                collection = Activator.CreateInstance(collectionType);
                foreach (object element in propertyValue)
                {
                    addMethod.Invoke(collection, new object[] { element });
                }
            }
            propertyInfo.SetValue(targetResource, collection, null);
        }
示例#12
0
        public virtual void RemoveReferenceFromCollection(object targetResource, string propertyName, object resourceToBeRemoved)
        {
            ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource");
            ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName");
            ExceptionUtilities.CheckArgumentNotNull(resourceToBeRemoved, "resourceToBeRemoved");
            UpdatableToken.AssertIsToken(targetResource, "targetResource");
            resourceToBeRemoved = UpdatableToken.AssertIsTokenAndResolve(resourceToBeRemoved, "resourceToBeRemoved");
            IList list = this.GetValue(targetResource, propertyName) as IList;

            ExceptionUtilities.CheckObjectNotNull(list, "Property '{0}' on type '{1}' was not a list", new object[] { propertyName, targetResource.GetType().Name });
            this.pendingChanges.Add(delegate {
                list.Remove(resourceToBeRemoved);
            });
        }
示例#13
0
        public virtual void DeleteResource(object targetResource)
        {
            ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource");
            targetResource = UpdatableToken.AssertIsTokenAndResolve(targetResource, "targetResource");
            string resourceSetName = this.GetResourceSetOfTargetResource(targetResource);

            ExceptionUtilities.CheckObjectNotNull(resourceSetName, "Unable to find set of the resource to delete", new object[0]);
            this.deletedObjects.Add(targetResource);
            IList resourceSetList = this.GetResourceSetEntities(resourceSetName);

            this.DeleteAllReferences(targetResource);
            this.pendingChanges.Add(delegate {
                resourceSetList.Remove(targetResource);
            });
        }
示例#14
0
        /// <summary>
        /// Sets the value of the given reference property on the target object
        /// </summary>
        /// <param name="targetResource">target object which defines the property</param>
        /// <param name="propertyName">name of the property whose value needs to be updated</param>
        /// <param name="propertyValue">value of the property</param>
        public virtual void SetReference(object targetResource, string propertyName, object propertyValue)
        {
            ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource");
            ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName");
            if (propertyValue != null)
            {
                UpdatableToken.AssertIsToken(propertyValue, "propertyValue");
            }

            // Note that we don't support bi-directional relationships so we only handle the one resource reference property in isolation.

            // Our reference properties are just like normal properties we just set the property value to the new value
            //   we don't perform any special actions for references.
            // So just call the SetValue which will do exactly that.
            this.SetValue(targetResource, propertyName, propertyValue);
        }
示例#15
0
        /// <summary>
        /// Sets the value of the given property on the target object
        /// </summary>
        /// <param name="targetResource">target object which defines the property</param>
        /// <param name="propertyName">name of the property whose value needs to be updated</param>
        /// <param name="propertyValue">value of the property</param>
        public virtual void SetValue(object targetResource, string propertyName, object propertyValue)
        {
            ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource");
            ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName");

            var token = UpdatableToken.AssertIsToken(targetResource, "targetResource");

            targetResource = token.Resource;

            // note that propertyValue might be a token itself, but GetValue will simply return whatever is stored in the token
            token.PendingPropertyUpdates[propertyName] = propertyValue;

            // Add a pending change to modify the value of the property
            this.pendingChanges.Add(() =>
            {
                Type t          = targetResource.GetType();
                PropertyInfo pi = t.GetProperty(propertyName);
                ExceptionUtilities.CheckObjectNotNull(pi, "Unable to find property '{0}' on type '{1}'", propertyName, targetResource.GetType().Name);

                string entitySetName = this.ReflectionMetadataHelper.FindSetNameForType(t);
                object generatedValue;
                if (this.TryGetStoreGeneratedValue(entitySetName, GetResourceTypeFullName(t), propertyName, out generatedValue))
                {
                    propertyValue = generatedValue;
                }

                if (this.IsCollectionProperty(pi))
                {
                    ExceptionUtilities.CheckObjectNotNull(propertyValue, "Collection property value was null");

                    var enumerable = propertyValue as IEnumerable;
                    ExceptionUtilities.CheckObjectNotNull(enumerable, "Collection property value was not an enumerable");

                    this.SetCollectionPropertyValue(targetResource, pi, enumerable);
                }
                else
                {
                    propertyValue = UpdatableToken.ResolveIfToken(propertyValue);
                    pi.SetValue(targetResource, propertyValue, null);
                }
            });
        }
示例#16
0
        /// <summary>
        /// Sets the concurrencyValues
        /// </summary>
        /// <param name="resourceCookie">The resource to be evaluated</param>
        /// <param name="checkForEquality">Determines whether to apply the equality check or not</param>
        /// <param name="concurrencyValues">The concurrency values to compare against</param>
        public virtual void SetConcurrencyValues(object resourceCookie, bool?checkForEquality, IEnumerable <KeyValuePair <string, object> > concurrencyValues)
        {
            ExceptionUtilities.CheckArgumentNotNull(resourceCookie, "resourceCookie");
            ExceptionUtilities.ThrowDataServiceExceptionIfFalse(checkForEquality.HasValue, 417, "Missing concurrency token for update operation");
            ExceptionUtilities.Assert(checkForEquality.Value, "Should not be called with check for equality parameter equal to false");
            ExceptionUtilities.CheckArgumentNotNull(concurrencyValues, "concurrencyValues");

            // If-Match: *
            if (!concurrencyValues.Any())
            {
                return;
            }

            resourceCookie = UpdatableToken.AssertIsTokenAndResolve(resourceCookie, "resourceCookie");

            Dictionary <string, object> etags = this.GetConcurrencyValues(resourceCookie);

            bool matches = CompareETagValues(etags, concurrencyValues);

            ExceptionUtilities.ThrowDataServiceExceptionIfFalse(matches, 412, "Concurrency tokens do not match");
        }
示例#17
0
        public virtual object ResetResource(object resource)
        {
            ExceptionUtilities.CheckArgumentNotNull(resource, "resource");
            UpdatableToken token = UpdatableToken.AssertIsToken(resource, "resource");

            resource = token.Resource;
            token    = new UpdatableToken(resource);
            object newInstance = Activator.CreateInstance(resource.GetType());

            ExceptionUtilities.CheckObjectNotNull(newInstance, "Cannot reset resource because unable to creating new instance of type '{0}' returns null", new object[] { resource.GetType().Name });
            foreach (string propertyToReset in this.MetadataHelper.GetPropertiesToReset(GetResourceTypeFullName(resource.GetType())))
            {
                PropertyInfo pi = newInstance.GetType().GetProperty(propertyToReset);
                ExceptionUtilities.CheckObjectNotNull(pi, "Cannot reset resource because unable to find property '{0}'", new object[] { propertyToReset });
                object newValue = pi.GetValue(newInstance, null);
                this.pendingChanges.Add(delegate {
                    pi.SetValue(resource, newValue, null);
                });
                token.PendingPropertyUpdates[propertyToReset] = newValue;
            }
            return(token);
        }
示例#18
0
        public virtual object GetValue(object targetResource, string propertyName)
        {
            ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource");
            ExceptionUtilities.CheckArgumentNotNull(propertyName, "propertyName");
            UpdatableToken token = UpdatableToken.AssertIsToken(targetResource, "targetResource");

            if (token.PendingPropertyUpdates.ContainsKey(propertyName))
            {
                return(token.PendingPropertyUpdates[propertyName]);
            }
            targetResource = token.Resource;
            PropertyInfo pi = targetResource.GetType().GetProperty(propertyName);

            ExceptionUtilities.CheckObjectNotNull(pi, "Cannot find the property '{0}' on type '{1}'", new object[] { propertyName, targetResource.GetType().Name });
            object value = pi.GetValue(targetResource, null);

            if ((value != null) && (pi.PropertyType.Assembly == base.GetType().Assembly))
            {
                ExceptionUtilities.Assert(!this.MetadataHelper.IsTypeAnEntityType(pi.PropertyType), "GetValue should never be called for reference properties. Type was '{0}', property was '{1}'", new object[] { pi.PropertyType.FullName, propertyName });
                value = new UpdatableToken(value);
            }
            return(value);
        }
示例#19
0
        /// <summary>
        /// Delete the given resource
        /// </summary>
        /// <param name="targetResource">resource that needs to be deleted</param>
        public virtual void DeleteResource(object targetResource)
        {
            ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource");

            targetResource = UpdatableToken.AssertIsTokenAndResolve(targetResource, "targetResource");

            string resourceSetName = this.GetResourceSetOfTargetResource(targetResource);

            ExceptionUtilities.CheckObjectNotNull(resourceSetName, "Unable to find set of the resource to delete");

            this.deletedObjects.Add(targetResource);

            IList resourceSetList = this.GetResourceSetEntities(resourceSetName);

            // Remove any any references this target resource has
            this.DeleteAllReferences(targetResource);

            // Add a pending change to remove the resource from the resource set
            this.pendingChanges.Add(() =>
            {
                resourceSetList.Remove(targetResource);
            });
        }
示例#20
0
        private UpdatableToken InstantiateResourceType(string fullTypeName)
        {
            Type t = this.ReflectionMetadataHelper.FindClrTypeByFullName(fullTypeName);

            ExceptionUtilities.ThrowDataServiceExceptionIfFalse(!t.IsAbstract, 400, "Cannot create resource because type \"{0}\" is abstract", t.FullName);

            var instance = Activator.CreateInstance(t);
            var token    = new UpdatableToken(instance);

            foreach (var p in t.GetProperties().Where(p => p.CanWrite))
            {
                // make local variable so that lambdas below work
                var property = p;

                if (this.IsCollectionProperty(property))
                {
                    Type collectionType = this.GetCollectionPropertyType(GetResourceTypeFullName(t), property.Name);
                    if (collectionType != null)
                    {
                        var newCollection = Activator.CreateInstance(collectionType);
                        token.PendingPropertyUpdates[property.Name] = newCollection;
                        this.pendingChanges.Add(() => property.SetValue(instance, newCollection, null));
                    }
                }

                string entitySetName = this.ReflectionMetadataHelper.FindSetNameForType(t);
                object generatedValue;
                if (this.TryGetStoreGeneratedValue(entitySetName, fullTypeName, property.Name, out generatedValue))
                {
                    token.PendingPropertyUpdates[property.Name] = generatedValue;
                    this.pendingChanges.Add(() => property.SetValue(instance, generatedValue, null));
                }
            }

            return(token);
        }
示例#21
0
 public virtual object ResolveResource(object resource)
 {
     ExceptionUtilities.CheckArgumentNotNull(resource, "resource");
     return(UpdatableToken.AssertIsTokenAndResolve(resource, "resource"));
 }
示例#22
0
        /// <summary>
        /// Sets the value of a collection property
        /// </summary>
        /// <param name="targetResource">The resource to set the value on</param>
        /// <param name="propertyInfo">The property to set</param>
        /// <param name="propertyValue">The collection value</param>
        protected virtual void SetCollectionPropertyValue(object targetResource, PropertyInfo propertyInfo, IEnumerable propertyValue)
        {
            ExceptionUtilities.CheckArgumentNotNull(targetResource, "targetResource");
            ExceptionUtilities.CheckArgumentNotNull(propertyInfo, "propertyInfo");
            ExceptionUtilities.CheckArgumentNotNull(propertyValue, "propertyValue");

            Type collectionType = this.GetCollectionPropertyType(GetResourceTypeFullName(propertyInfo.ReflectedType), propertyInfo.Name);

            ExceptionUtilities.CheckObjectNotNull(collectionType, "Could not infer collection type for property");
            object collection;

            // need to go through the enumerable and resolve any tokens
            propertyValue = propertyValue.Cast <object>().Select(o => UpdatableToken.ResolveIfToken(o));

            // Algorithm for setting a collection value:
            // - Get a collection of the correct instance type
            //   - Look for a constructor that takes a non-generic IEnumerable, if one is found invoke it
            //   - If the type is generic
            //     - look for a constuctor taking IEnumerable<T>, if one is found invoke it
            //     - look for an Add method taking T, if one is found use default constructor and add each item
            //   - look for an untyped Add method, if one is found use default constructor and add each item
            // - Set the property normally, using the new collection instance
            var enumerableConstructor = collectionType.GetConstructor(new Type[] { typeof(IEnumerable) });

            if (enumerableConstructor != null)
            {
                // invoke the IEnumerable constructor with the property value
                collection = enumerableConstructor.Invoke(new object[] { propertyValue });
            }
            else if (collectionType.IsGenericType && collectionType.GetGenericArguments().Count() == 1)
            {
                // determine the element type
                var typeArgument = collectionType.GetGenericArguments().Single();

                // look for a constructor taking IEnumerable<T>
                var typedEnumerableConstructor = collectionType.GetConstructor(new Type[] { typeof(IEnumerable <>).MakeGenericType(typeArgument) });

                if (typedEnumerableConstructor != null)
                {
                    // convert the IEnumerable into IEnumerable<T> using Enumerable.Cast
                    var typedEnumerable = typeof(Enumerable).GetMethod("Cast").MakeGenericMethod(typeArgument).Invoke(null, new object[] { propertyValue });

                    // invoke the constructor
                    collection = typedEnumerableConstructor.Invoke(new object[] { typedEnumerable });
                }
                else
                {
                    // look for an Add method accepting T
                    var typedAddMethod = collectionType.GetMethod("Add", new Type[] { typeArgument });

                    // for generic types, we must find either a constructor or an Add method
                    ExceptionUtilities.CheckObjectNotNull(typedAddMethod, "Could not find constructor or add method for type: " + collectionType.FullName);

                    // create a new instance, and add each item
                    collection = Activator.CreateInstance(collectionType);
                    foreach (var element in propertyValue)
                    {
                        typedAddMethod.Invoke(collection, new object[] { element });
                    }
                }
            }
            else
            {
                // look for an Add method
                var addMethod = collectionType.GetMethod("Add");

                // fail if no method is found
                ExceptionUtilities.CheckObjectNotNull(addMethod, "Could not find constructor or add method for type: " + collectionType.FullName);

                // create a new instance and add each item
                collection = Activator.CreateInstance(collectionType);
                foreach (var element in propertyValue)
                {
                    addMethod.Invoke(collection, new object[] { element });
                }
            }

            // set the new collection instance as the value
            propertyInfo.SetValue(targetResource, collection, null);
        }