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