private static TN IfElementIs <TN, TE>(IDeclaredElement element,
                                               DeclaredElementToName <TN, TE> map,
                                               ISubstitution substitution,
                                               TN unknownName,
                                               IDictionary <DeclaredElementInstance, IName> seenElements)
            where TE : class, IDeclaredElement
            where TN : class, IName
        {
            var specificElement = element as TE;

            if (specificElement == null)
            {
                return(null);
            }
            var dei = new DeclaredElementInstance(element, substitution);

            // exit if we encounter a recursive type, e.g., delegate IList<D> D();
            if (seenElements.ContainsKey(dei))
            {
                return((TN)seenElements[dei]);
            }
            // this makes us default to the unknownName, if we reencounter an element while resolving it
            seenElements[dei] = unknownName;
            // after this call we have resolved the element and cached the result
            seenElements[dei] = IsMissingDeclaration(specificElement)
                ? unknownName
                : map(specificElement, substitution, seenElements);
            return((TN)seenElements[dei]);
        }
        private static ITypeName IfElementIs <TE>(ITypeElement typeElement,
                                                  DeclaredElementToName <ITypeName, TE> map,
                                                  ISubstitution substitution,
                                                  IDictionary <DeclaredElementInstance, IName> seenElements,
                                                  ITypeName unknownName)
            where TE : class, IDeclaredElement
        {
            var specificElement = typeElement as TE;

            if (specificElement == null)
            {
                return(null);
            }
            return(IsMissingDeclaration(specificElement)
                ? unknownName
                : map(specificElement, substitution, seenElements));
        }