/// <summary> /// Gets the value of a given property on the given task. /// </summary> internal object GetPropertyValue(ITask task, TaskPropertyInfo property) { ErrorUtilities.VerifyThrowArgumentNull(task, "task"); ErrorUtilities.VerifyThrowArgumentNull(property, "property"); IGeneratedTask generatedTask = task as IGeneratedTask; if (generatedTask != null) { return(generatedTask.GetPropertyValue(property)); } else { ReflectableTaskPropertyInfo propertyInfo = property as ReflectableTaskPropertyInfo; if (propertyInfo != null) { return(propertyInfo.Reflection.GetValue(task, null)); } else { ErrorUtilities.ThrowInternalError("Task does not implement IGeneratedTask and we don't have {0} either.", typeof(ReflectableTaskPropertyInfo).Name); throw new InternalErrorException(); // unreachable } } }
/// <summary> /// Populate the cache of PropertyInfos for this type /// </summary> private void PopulatePropertyInfoCacheIfNecessary() { if (_propertyInfoCache == null) { _propertyInfoCache = new Dictionary <string, TaskPropertyInfo>(StringComparer.OrdinalIgnoreCase); // Use a HybridDictionary because these are usually very small _namesOfPropertiesWithRequiredAttribute = new HybridDictionary <string, string>(StringComparer.OrdinalIgnoreCase); _namesOfPropertiesWithOutputAttribute = new HybridDictionary <string, string>(StringComparer.OrdinalIgnoreCase); _namesOfPropertiesWithAmbiguousMatches = new HybridDictionary <string, string>(StringComparer.OrdinalIgnoreCase); bool taskTypeImplementsIGeneratedTask = typeof(IGeneratedTask).IsAssignableFrom(_taskFactory.TaskType); TaskPropertyInfo[] propertyInfos = _taskFactory.GetTaskParameters(); for (int i = 0; i < propertyInfos.Length; i++) { // If the task implements IGeneratedTask, we must use the TaskPropertyInfo the factory gives us. // Otherwise, we never have to hand the TaskPropertyInfo back to the task or factory, so we replace // theirs with one of our own that will allow us to cache reflection data per-property. TaskPropertyInfo propertyInfo = propertyInfos[i]; if (!taskTypeImplementsIGeneratedTask) { propertyInfo = new ReflectableTaskPropertyInfo(propertyInfo, _taskFactory.TaskType); } try { _propertyInfoCache.Add(propertyInfo.Name, propertyInfo); } catch (ArgumentException) { // We have encountered a duplicate entry in our hashtable; if we had used BindingFlags.IgnoreCase this // would have produced an AmbiguousMatchException. In the old code, before this cache existed, // that wouldn't have been thrown unless and until the project actually tried to set this ambiguous parameter. // So rather than fail here, we store a list of ambiguous names and throw later, when one of them // is requested. _namesOfPropertiesWithAmbiguousMatches[propertyInfo.Name] = String.Empty; } if (propertyInfos[i].Required) { // we have a require attribute defined, keep a record of that _namesOfPropertiesWithRequiredAttribute[propertyInfo.Name] = String.Empty; } if (propertyInfos[i].Output) { // we have a output attribute defined, keep a record of that _namesOfPropertiesWithOutputAttribute[propertyInfo.Name] = String.Empty; } } // Toss the dictionaries if we can as often they are empty (at least the last three are) _propertyInfoCache = (_propertyInfoCache.Count == 0) ? ReadOnlyEmptyDictionary <string, TaskPropertyInfo> .Instance : _propertyInfoCache; _namesOfPropertiesWithRequiredAttribute = (_namesOfPropertiesWithRequiredAttribute.Count == 0) ? ReadOnlyEmptyDictionary <string, string> .Instance : _namesOfPropertiesWithRequiredAttribute; _namesOfPropertiesWithOutputAttribute = (_namesOfPropertiesWithOutputAttribute.Count == 0) ? ReadOnlyEmptyDictionary <string, string> .Instance : _namesOfPropertiesWithOutputAttribute; _namesOfPropertiesWithAmbiguousMatches = (_namesOfPropertiesWithAmbiguousMatches.Count == 0) ? ReadOnlyEmptyDictionary <string, string> .Instance : _namesOfPropertiesWithAmbiguousMatches; } }
/// <summary> /// Gets all of the parameters on the task. /// </summary> public TaskPropertyInfo[] GetTaskParameters() { PropertyInfo[] infos = TaskType.GetProperties(BindingFlags.Instance | BindingFlags.Public); var propertyInfos = new TaskPropertyInfo[infos.Length]; for (int i = 0; i < infos.Length; i++) { propertyInfos[i] = new ReflectableTaskPropertyInfo(infos[i]); } return propertyInfos; }
/// <summary> /// Sets the given property on the task. /// </summary> internal void SetPropertyValue(ITask task, TaskPropertyInfo property, object value) { ErrorUtilities.VerifyThrowArgumentNull(task, "task"); ErrorUtilities.VerifyThrowArgumentNull(property, "property"); IGeneratedTask generatedTask = task as IGeneratedTask; if (generatedTask != null) { generatedTask.SetPropertyValue(property, value); } else { ReflectableTaskPropertyInfo propertyInfo = (ReflectableTaskPropertyInfo)property; propertyInfo.Reflection.SetValue(task, value, null); } }
/// <summary> /// Populate the cache of PropertyInfos for this type /// </summary> private void PopulatePropertyInfoCacheIfNecessary() { if (_propertyInfoCache == null) { _propertyInfoCache = new Dictionary<string, TaskPropertyInfo>(StringComparer.OrdinalIgnoreCase); // Use a HybridDictionary because these are usually very small _namesOfPropertiesWithRequiredAttribute = new HybridDictionary<string, string>(StringComparer.OrdinalIgnoreCase); _namesOfPropertiesWithOutputAttribute = new HybridDictionary<string, string>(StringComparer.OrdinalIgnoreCase); _namesOfPropertiesWithAmbiguousMatches = new HybridDictionary<string, string>(StringComparer.OrdinalIgnoreCase); bool taskTypeImplementsIGeneratedTask = typeof(IGeneratedTask).IsAssignableFrom(_taskFactory.TaskType); TaskPropertyInfo[] propertyInfos = _taskFactory.GetTaskParameters(); for (int i = 0; i < propertyInfos.Length; i++) { // If the task implements IGeneratedTask, we must use the TaskPropertyInfo the factory gives us. // Otherwise, we never have to hand the TaskPropertyInfo back to the task or factory, so we replace // theirs with one of our own that will allow us to cache reflection data per-property. TaskPropertyInfo propertyInfo = propertyInfos[i]; if (!taskTypeImplementsIGeneratedTask) { propertyInfo = new ReflectableTaskPropertyInfo(propertyInfo, _taskFactory.TaskType); } try { _propertyInfoCache.Add(propertyInfo.Name, propertyInfo); } catch (ArgumentException) { // We have encountered a duplicate entry in our hashtable; if we had used BindingFlags.IgnoreCase this // would have produced an AmbiguousMatchException. In the old code, before this cache existed, // that wouldn't have been thrown unless and until the project actually tried to set this ambiguous parameter. // So rather than fail here, we store a list of ambiguous names and throw later, when one of them // is requested. _namesOfPropertiesWithAmbiguousMatches[propertyInfo.Name] = String.Empty; } if (propertyInfos[i].Required) { // we have a require attribute defined, keep a record of that _namesOfPropertiesWithRequiredAttribute[propertyInfo.Name] = String.Empty; } if (propertyInfos[i].Output) { // we have a output attribute defined, keep a record of that _namesOfPropertiesWithOutputAttribute[propertyInfo.Name] = String.Empty; } } // Toss the dictionaries if we can as often they are empty (at least the last three are) _propertyInfoCache = (_propertyInfoCache.Count == 0) ? ReadOnlyEmptyDictionary<string, TaskPropertyInfo>.Instance : _propertyInfoCache; _namesOfPropertiesWithRequiredAttribute = (_namesOfPropertiesWithRequiredAttribute.Count == 0) ? ReadOnlyEmptyDictionary<string, string>.Instance : _namesOfPropertiesWithRequiredAttribute; _namesOfPropertiesWithOutputAttribute = (_namesOfPropertiesWithOutputAttribute.Count == 0) ? ReadOnlyEmptyDictionary<string, string>.Instance : _namesOfPropertiesWithOutputAttribute; _namesOfPropertiesWithAmbiguousMatches = (_namesOfPropertiesWithAmbiguousMatches.Count == 0) ? ReadOnlyEmptyDictionary<string, string>.Instance : _namesOfPropertiesWithAmbiguousMatches; } }