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); } }); }
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); }
/// <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); } }); }
/// <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); }