/// <summary>
        /// Gets the rule name for an item type.
        /// </summary>
        /// <param name="itemType">The item type to get a rule name for.</param>
        /// <param name="catalogs">The catalog snapshot to use to find the rule name.</param>
        /// <param name="allowNull">Whether or not to allow a null result for a missing or malformed rule.</param>
        /// <returns>The matching rule name.</returns>
        public string GetRuleNameFromItemType(string itemType,
                                              IProjectCatalogSnapshot catalogs,
                                              bool allowNull = false)
        {
            Requires.NotNullOrEmpty(itemType, nameof(itemType));
            Requires.NotNull(catalogs, nameof(catalogs));

            string ruleName;

            lock (_syncObject)
            {
                if (!_itemTypeToRuleName.TryGetValue(itemType, out ruleName))
                {
                    ruleName = GetRuleNameByItemType(catalogs, PropertyPageContexts.Project, itemType)
                               ?? GetRuleNameByItemType(catalogs, PropertyPageContexts.File, itemType);

                    if (ruleName != null)
                    {
                        _ruleNameToItemType[ruleName] = itemType;
                        _itemTypeToRuleName[itemType] = ruleName;
                    }
                }
            }

            ProjectErrorUtilities.VerifyThrowProjectException(ruleName != null || allowNull,
                                                              VSResources.NoItemTypeForRule,
                                                              itemType);

            return(ruleName);
        }
        /// <summary>
        /// Gets the item type for a given rule.
        /// </summary>
        /// <param name="ruleName">The name of the rule to get an item type for.</param>
        /// <param name="catalogs">The catalog snapshot to use to find the item type.</param>
        /// <param name="allowNull">Whether or not to allow a null result for a missing or malformed rule.</param>
        /// <returns>The matching item type.</returns>
        public string GetItemTypeFromRuleName(string ruleName,
                                              IProjectCatalogSnapshot catalogs,
                                              bool allowNull = false)
        {
            Requires.NotNullOrEmpty(ruleName, nameof(ruleName));
            Requires.NotNull(catalogs, nameof(catalogs));

            string itemType;

            lock (_syncObject)
            {
                if (!_ruleNameToItemType.TryGetValue(ruleName, out itemType))
                {
                    var rule = catalogs.GetSchema(PropertyPageContexts.Project, ruleName)
                               ?? catalogs.GetSchema(PropertyPageContexts.File, ruleName);
                    itemType = rule != null ? rule.DataSource.ItemType : null;

                    if (itemType != null)
                    {
                        _ruleNameToItemType[ruleName] = itemType;
                        _itemTypeToRuleName[itemType] = ruleName;
                    }
                }
            }

            ProjectErrorUtilities.VerifyThrowProjectException(
                itemType != null || allowNull, VSResources.NoItemTypeForRule, ruleName);

            return(itemType);
        }