File: System\Windows\Markup\XamlTypeMapper.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\src\PresentationFramework\PresentationFramework.csproj (PresentationFramework)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
//
// Description:
//  Maps namespaceURI and LocalName to appropriate element, properties, and events.
//
 
using System;
using System.IO;
using MS.Utility;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.ComponentModel;
using System.Collections.Specialized;
using System.Runtime.CompilerServices;
using System.Diagnostics;
using System.Reflection;
 
#if !PBTCOMPILER
 
using MS.Internal;  // CriticalExceptions
 
#endif
 
// Disabling 1634 and 1691:
// In order to avoid generating warnings about unknown message numbers and
// unknown pragmas when compiling C# source code with the C# compiler,
// you need to disable warnings 1634 and 1691. (Presharp Documentation)
#pragma warning disable 1634, 1691
 
#if PBTCOMPILER
namespace MS.Internal.Markup
#else
namespace System.Windows.Markup
#endif
{
    ///<summary>
    /// Handles mapping between XML NamepaceURI and .NET namespace types
    ///</summary>
#if PBTCOMPILER
    internal class XamlTypeMapper
#else
    public partial class XamlTypeMapper
#endif
    {
#region Public
 
#region Methods
 
#if !PBTCOMPILER
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="assemblyNames">Assemblies XamlTypeMapper should use when resolving XAML</param>
        public XamlTypeMapper(string[] assemblyNames)
        {
            if(null == assemblyNames)
            {
                throw new ArgumentNullException( "assemblyNames" );
            }
 
            _assemblyNames = assemblyNames;
            _namespaceMaps = null;
        }
#endif
 
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="assemblyNames">Assemblies XamlTypeMapper should use when resolving XAML</param>
        /// <param name="namespaceMaps">NamespaceMap the XamlTypeMapper should use when resolving XAML</param>
        public XamlTypeMapper(
            string[] assemblyNames,
            NamespaceMapEntry[] namespaceMaps)
        {
            if(null == assemblyNames)
            {
                throw new ArgumentNullException( "assemblyNames" );
            }
 
            _assemblyNames = assemblyNames;
            _namespaceMaps = namespaceMaps;
#if PBTCOMPILER
            _hasInternals = false;
            _hasLocalReference = false;
#endif
        }
 
        /// <summary>
        /// Helper to map an Xaml tag to a DotNet Type
        /// </summary>
        /// <remarks>
        /// Example:<para/>
        ///     If the xml contained the tags <base:Button xmlns:base="AvalonBase"/>
        ///     you would call XamlTypeMapper.GetType("AvalonBase","Button");
        ///     <para/>
        ///     Note the XmlNamespace "AvalonBase" is the actual namespace value, not
        ///     the base: prefix.
        /// </remarks>
        /// <param name="xmlNamespace">NamespaceURI of tag</param>
        /// <param name="localName">localName of the Tag</param>
        /// <returns>Type for the object. If no type was found NULL is returned</returns>
        public Type GetType(
            string xmlNamespace,
            string localName)
        {
            if(null == xmlNamespace)
            {
                throw new ArgumentNullException( "xmlNamespace" );
            }
            if(null == localName)
            {
                throw new ArgumentNullException( "localName" );
            }
 
            TypeAndSerializer typeAndSerializer =
                GetTypeOnly(xmlNamespace,localName);
 
            return typeAndSerializer != null ? typeAndSerializer.ObjectType : null;
        }
 
#if !PBTCOMPILER
        /// <summary>
        ///  Programmatic counterpart to the <?Mapping ... ?> XAML PI.  For example, <para/>
        ///    <?Mapping XmlNamespace="swc" ClrNamespace="System.Windows.ComponentModel" Assembly="PresentationFramework" ?>
        /// </summary>
        /// <param name="xmlNamespace">
        /// The "swc" argument in the mapping PI example.
        /// </param>
        /// <param name="clrNamespace">
        /// The "System.Windows.ComponentModel" argument in the mapping PI example.
        /// </param>
        /// <param name="assemblyName">
        /// The "PresentationFramework" argument in the mapping PI example.
        /// </param>
        public void AddMappingProcessingInstruction(
            string  xmlNamespace,
            string  clrNamespace,
            string  assemblyName )
        {
            if( null == xmlNamespace )
            {
                throw new ArgumentNullException("xmlNamespace");
            }
            if( null == clrNamespace )
            {
                throw new ArgumentNullException("clrNamespace");
            }
            if( null == assemblyName )
            {
                throw new ArgumentNullException("assemblyName");
            }
 
            // Parameter validation : Check for String.Empty as well?
 
            // Add mapping to the table keyed by xmlNamespace
            ClrNamespaceAssemblyPair pair = new ClrNamespaceAssemblyPair(clrNamespace, assemblyName);
            PITable[xmlNamespace] = pair;
 
            // Add mapping to the table keyed by assembly and clrnamespace
            string upperAssemblyName = assemblyName.ToUpper(
                                              TypeConverterHelper.InvariantEnglishUS);
            String fullName = $"{clrNamespace}#{upperAssemblyName}";
 
            _piReverseTable[fullName] = xmlNamespace;
 
            // Add mapping to the SchemaContext
            if (_schemaContext != null)
            {
                _schemaContext.SetMappingProcessingInstruction(xmlNamespace, pair);
            }
        }
#endif
        /// <summary>
        ///     This allows specifying a path to use when loading the named assembly.
        /// </summary>
        /// <param name="assemblyName">
        /// The short name of the assembly, with no extension or path specified
        /// </param>
        /// <param name="assemblyPath">
        /// The file path of the assembly
        /// </param>
        public void SetAssemblyPath(
            string assemblyName,
            string assemblyPath)
        {
            if( null == assemblyName )
            {
                throw new ArgumentNullException("assemblyName");
            }
            if( null == assemblyPath )
            {
                throw new ArgumentNullException("assemblyPath");
            }
            if (assemblyPath == string.Empty)
            {
                _lineNumber = 0;  // Public API, so we don't know the line number.
                ThrowException(nameof(SR.ParserBadAssemblyPath));
            }
            if (assemblyName == string.Empty)
            {
                _lineNumber = 0;  // Public API, so we don't know the line number.
                ThrowException(nameof(SR.ParserBadAssemblyName));
            }
 
            string asmName = assemblyName.ToUpper(CultureInfo.InvariantCulture);
            lock (_assemblyPathTable)
            {
                _assemblyPathTable[asmName] = assemblyPath;
            }
 
#if PBTCOMPILER
            PreLoadDefaultAssemblies(asmName, assemblyPath);
#else
            // Allow people to reset the path of previously loaded assemblies
            // so they can be loaded again.   The is the Dev build/load/build/load
            // Designer scenario.  (Don't mess with GACed assemblies)
            Assembly assem = ReflectionHelper.GetAlreadyLoadedAssembly(asmName);
            if (assem != null
#if NETFX
                 && !assem.GlobalAssemblyCache
#endif
                )
            {
                ReflectionHelper.ResetCacheForAssembly(asmName);
                // No way to reset SchemaContext at assembly granularity, so just reset the whole context
                if (_schemaContext != null)
                {
                    _schemaContext = null;
                }
            }
#endif
        }
 
#endregion Methods
 
#region Properties
 
        /// <summary>
        ///  Instance of XamlTypeMapper to use if none is specified in a
        ///  ParserContext.  XamlTypeMapper returned is the internal default.
        /// </summary>
        public static XamlTypeMapper DefaultMapper
        {
            get
            {
                return XmlParserDefaults.DefaultMapper;
            }
        }
 
#endregion Properties
 
#endregion Public
 
#region Internal
 
#region Initialization
 
#if !PBTCOMPILER
        ///<summary>
        /// Initialize the XamlTypeMapper so that it is ready for a parse operation.
        ///</summary>
        internal void Initialize()
        {
            _typeLookupFromXmlHashtable.Clear();
            _namespaceMapHashList.Clear();
            _piTable.Clear();
            _piReverseTable.Clear();
            lock (_assemblyPathTable)
            {
                _assemblyPathTable.Clear();
            }
            _referenceAssembliesLoaded = false;
        }
#endif
 
        // Return a new XamlTypeMapper that has the same instance variables as this instance,
        // will all complex properties deep copied.
#if !PBTCOMPILER
        internal XamlTypeMapper Clone()
        {
            XamlTypeMapper newMapper = new XamlTypeMapper(_assemblyNames.Clone() as string[]);
 
            newMapper._mapTable = _mapTable;
            newMapper._referenceAssembliesLoaded = _referenceAssembliesLoaded;
            newMapper._lineNumber = _lineNumber;
            newMapper._linePosition = _linePosition;
 
            newMapper._namespaceMaps = _namespaceMaps.Clone() as NamespaceMapEntry[];
            newMapper._typeLookupFromXmlHashtable = _typeLookupFromXmlHashtable.Clone() as Hashtable;
            newMapper._namespaceMapHashList = _namespaceMapHashList.Clone() as Hashtable;
            newMapper._typeInformationCache = CloneHybridDictionary(_typeInformationCache);
            newMapper._piTable = CloneHybridDictionary(_piTable);
            newMapper._piReverseTable = CloneStringDictionary(_piReverseTable);
            newMapper._assemblyPathTable = CloneHybridDictionary(_assemblyPathTable);
 
            return newMapper;
        }
#endif
 
#if !PBTCOMPILER
        private HybridDictionary CloneHybridDictionary(HybridDictionary dict)
        {
            HybridDictionary newDict = new HybridDictionary(dict.Count);
            foreach ( DictionaryEntry de in dict )
            {
                newDict.Add(de.Key, de.Value);
            }
            return newDict;
        }
#endif
 
#if !PBTCOMPILER
        private Dictionary<string, string> CloneStringDictionary(Dictionary<string, string> dict)
        {
            Dictionary<string, string> newDict = new Dictionary<string, string>();
            foreach (KeyValuePair<string, string> kvp in dict)
            {
                newDict.Add(kvp.Key, kvp.Value);
            }
            return newDict;
        }
#endif
 
#endregion Initialization
 
#region Assemblies
 
        ///<summary>
        /// Returns the assembly path for the passed assembly.  If none, return null.
        ///</summary>
        internal string AssemblyPathFor(string assemblyName)
        {
            string path = null;
            if (assemblyName != null)
            {
                // This method is used by SchemaContext, which needs to be thread-safe, so lock around it
                lock (_assemblyPathTable)
                {
                    path = _assemblyPathTable[assemblyName.ToUpper(
                                            CultureInfo.InvariantCulture)] as string;
                }
            }
 
#if PBTCOMPILER

            if (path == null)
            {
                // If the assembly name contains full assembly name, we should use the short
                // assembly name to search the assembly path cache table.
 
                int indexComma = assemblyName.IndexOf(",", StringComparison.Ordinal);
 
                if (indexComma > 0)
                {
                    string assemblyShortName = assemblyName.Substring(0, indexComma).ToUpper(CultureInfo.InvariantCulture);
                    path = _assemblyPathTable[assemblyShortName] as String;
                }
            }
#endif
 
            return path;
        }
 
        /// <summary>
        /// Load assemblies that are in the referenced assembly list passed to the XamlTypeMapper
        /// by the compiler.  Don't load known assemblies that should already be present,
        /// since the references may not be the correct versions.
        /// </summary>
        private bool LoadReferenceAssemblies()
        {
            if (!_referenceAssembliesLoaded)
            {
                _referenceAssembliesLoaded = true;
                foreach (DictionaryEntry entry in _assemblyPathTable)
                {
                    ReflectionHelper.LoadAssembly(entry.Key as String, entry.Value as String);
                }
                return true;
            }
            else
            {
                // Already loaded, so they don't need to be loaded again
                return false;
            }
        }
 
#endregion Assemblies
 
#region AssemblyLoading
 
#if  PBTCOMPILER

        private void PreLoadDefaultAssemblies(string asmName, string asmPath)
        {
            if (AssemblyWB == null && string.Equals(asmName, _assemblyNames[0], StringComparison.OrdinalIgnoreCase))
            {
                AssemblyWB = ReflectionHelper.LoadAssembly(asmName, asmPath);
            }
            else if (AssemblyPC == null && string.Equals(asmName, _assemblyNames[1], StringComparison.OrdinalIgnoreCase))
            {
                AssemblyPC = ReflectionHelper.LoadAssembly(asmName, asmPath);
            }
            else if (AssemblyPF == null && string.Equals(asmName, _assemblyNames[2], StringComparison.OrdinalIgnoreCase))
            {
                AssemblyPF = ReflectionHelper.LoadAssembly(asmName, asmPath);
            }
            else if (string.Equals(asmName, "SYSTEM.XML", StringComparison.OrdinalIgnoreCase))
            {
                // make sure System.Xml is at least loaded as ReflectionOnly
                ReflectionHelper.LoadAssembly(asmName, asmPath);
            }
            else if (string.Equals(asmName, "SYSTEM", StringComparison.OrdinalIgnoreCase))
            {
                // make sure System is at least loaded as ReflectionOnly
                ReflectionHelper.LoadAssembly(asmName, asmPath);
            }
        }
#endif
 
#endregion AssemblyLoading
 
        #region Events
 
#if !PBTCOMPILER
 
        /// <summary>
        /// Helper to map an Attribute to a RoutedEvent
        /// </summary>
        /// <remarks>
        ///    Example: <para/>
        ///     If the xaml contained the tag <base:Button base:Click="MyClick" xmlns:base="BaseXmlNs"/>
        ///     you would call <para/>
        ///
        ///         Type owner = XamlTypeMapper.GetType("BaseXmlNs","Button"); <para/>
        ///         RoutedEvent = XamlTypeMapper.GetRoutedEvent(owner,"MyClick","BaseXmlNs");
        /// </remarks>
        /// <param name="owner">Type of the owner</param>
        /// <param name="xmlNamespace">Xml NamespaceURI of the attribute</param>
        /// <param name="localName">Local name of the attribute</param>
        /// <returns>The RoutedEvent ID or null if no match was found</returns>
        /// <ExternalAPI/>
        internal RoutedEvent GetRoutedEvent(
            Type   owner,
            string xmlNamespace,
            string localName)
        {
            Type baseType = null;
            string dynamicObjectName = null;
 
            if(null == localName)
            {
                throw new ArgumentNullException( "localName" );
            }
            if(null == xmlNamespace)
            {
                throw new ArgumentNullException( "xmlNamespace" );
            }
            if (owner != null && !ReflectionHelper.IsPublicType(owner))
            {
                _lineNumber = 0;  // Public API, so we don't know the line number.
                ThrowException(nameof(SR.ParserOwnerEventMustBePublic), owner.FullName );
            }
 
            RoutedEvent Event = GetDependencyObject(true,owner,xmlNamespace,
                localName,ref baseType,ref dynamicObjectName)
                as RoutedEvent;
 
            return Event;
        }
 
#endif
 
#endregion Events
 
#region Properties
 
#if !PBTCOMPILER
        ///<summary>
        /// Converts the string representation of an Attribute Value to an appropriate
        /// Type for the Property.  This handles use of type converters and the special
        /// *prefix:Type.Field syntax for enums, static properties and fields.
        /// </summary>
        ///<param name="targetObject">Target object that the property needs to be set on</param>
        ///<param name="propType">Type of the property</param>
        ///<param name="propName">Name of the property.  This is used only for
        ///                       error reporting and some pre-validation</param>
        ///<param name="dpOrPiOrFi">DependencyProperty or PropertyInfo or FieldInfo. This is used
        ///         for evaluating the TypeConverter to be used for conversion</param>
        ///<param name="typeContext">Context for the type converter</param>
        ///<param name="parserContext">Context for enum, field and property resolution</param>
        ///<param name="value">string value of the property the Attribute</param>
        ///<param name="converterTypeId">typeId of converter to use for paring the attribute value</param>
        ///<returns>
        /// An Object for the attribute value is returned.
        /// Null is returned if no TypeConverter for the Property type.
        ///</returns>
        internal Object ParseProperty(
            object                 targetObject,
            Type                   propType,
            string                 propName,
            object                 dpOrPiOrFi,
            ITypeDescriptorContext typeContext,
            ParserContext          parserContext,
            string                 value,
            short                  converterTypeId)
        {
            _lineNumber = parserContext != null ? parserContext.LineNumber : 0;
            _linePosition = parserContext != null ? parserContext.LinePosition : 0;
 
            // If value is to be converted to a string, just return the string itself instead of
            // going needlessly through the TC. But check that the target prop Type can accept strings.
            if (converterTypeId < 0 && ((short)-converterTypeId == (short)KnownElements.StringConverter))
            {
                if (propType == typeof(object) || propType == typeof(string))
                {
                    return value;
                }
                else
                {
                    string message = SR.Format(SR.ParserCannotConvertPropertyValueString, value, propName, propType.FullName);
                    XamlParseException.ThrowException(parserContext, _lineNumber, _linePosition, message, null);
                }
            }
 
            Object obj = null;   // Object to return
            TypeConverter typeConvert;
 
            if (converterTypeId != 0)
            {
                typeConvert = parserContext.MapTable.GetConverterFromId(converterTypeId, propType, parserContext);
            }
            else
            {
                // NOTE: This may still be a known converter. This is typically the case when adding
                // a text Record. This should also be potentially optimized by resolving & writing out the
                // TC at compile time.
 
                // Reflect for per property type converter or type converter based on the property's type
                typeConvert = GetPropertyConverter(propType, dpOrPiOrFi);
 
                #if DEBUG
                if( propType.Assembly.FullName == "PresentationFramework"
                    ||
                    propType.Assembly.FullName == "PresentationCore"
                    ||
                    propType.Assembly.FullName == "WindowsBase" )
                {
                    Debug.WriteLine($"Reflected for type converter on {propType.Name}.{propName}");
                }
                #endif
            }
 
#if !STRESS
            try
            {
#endif
                obj =  typeConvert.ConvertFromString(typeContext, TypeConverterHelper.InvariantEnglishUS, value);
 
                if( TraceMarkup.IsEnabled )
                {
                    TraceMarkup.TraceActivityItem( TraceMarkup.TypeConvert,
                                                 typeConvert,
                                                 value,
                                                 obj );
                }
#if !STRESS
            }
            catch (Exception e)
            {
                if( CriticalExceptions.IsCriticalException(e) || e is XamlParseException )
                {
                    throw;
                }
 
                // If the targetObject can provide a fallback value for this property then use that instead
 
                IProvidePropertyFallback iProvidePropertyFallback = targetObject as IProvidePropertyFallback;
                if (iProvidePropertyFallback != null && iProvidePropertyFallback.CanProvidePropertyFallback(propName))
                {
                    obj = iProvidePropertyFallback.ProvidePropertyFallback(propName, e);
 
                    if( TraceMarkup.IsEnabled )
                    {
                        TraceMarkup.TraceActivityItem( TraceMarkup.TypeConvertFallback,
                                                     typeConvert,
                                                     value,
                                                     obj );
                    }
                }
 
                // If we got the default object TypeConverter, then we know the conversion will
                // fail, so create a more meaningful error message here.
                else if (typeConvert.GetType() == typeof(TypeConverter))
                {
                    string message;
                    if( propName != string.Empty )
                    {
                        // <SomeElement SomeProp="SomeText"/> and there's no TypeConverter
                        //  to handle converting "SomeText" into an instance of something
                        //  that can be set into SomeProp.
                        message = SR.Format(SR.ParserDefaultConverterProperty, propType.FullName, propName, value);
                    }
                    else
                    {
                        // <SomeElement>SomeText</SomeElement> and there's no TypeConverter
                        //  associated with the type SomeElement
                        message = SR.Format(SR.ParserDefaultConverterElement, propType.FullName, value);
                    }
                    XamlParseException.ThrowException(parserContext, _lineNumber, _linePosition, message, null);
                }
                else
                {
                    string message = TypeConverterFailure( value, propName, propType.FullName );
                    XamlParseException.ThrowException(parserContext, _lineNumber, _linePosition, message, e);
                }
            }
#endif
 
            // Verify that the type converter actually gave us an instance of the correct object type.
            if( obj != null )
            {
                if(!propType.IsAssignableFrom(obj.GetType()))
                {
                    string message = TypeConverterFailure( value, propName, propType.FullName );
 
                    XamlParseException.ThrowException(parserContext, _lineNumber, _linePosition, message, null);
                }
            }
 
            return obj;
        }
 
        private string TypeConverterFailure( string value, string propName, string propType )
        {
            string message;
 
            if( propName != string.Empty )
            {
                // We were called to do type conversion on a string that's been
                //  assigned in an element attribute, but failed for whatever reason.
                //
                //   <Rectangle Fill="Red"/>
                //
                // propName is 'Fill' in this case.
 
                message = SR.Format(SR.ParserCannotConvertPropertyValueString, value, propName, propType);
            }
            else
            {
                // We are being called by BamlRecordReader::GetObjectFromString
                //  which is not trying to convert a property. It's actually
                //  trying to get an element out of this.
                //
                //   <SolidColorBrush>Red</SolidColorBrush>
                //
                // There is no associated propName available in this case, so we
                //  give a different error message.
 
                message = SR.Format(SR.ParserCannotConvertInitializationText, value, propType );
            }
            return message;
        }
#endif
 
        // ValidateNames does Name validation, and ValidateEnums does enum
        // name validation.  Note that both must be called to determine if a
        // property is valid before it is set, but the order is not important.  Hence
        // ValidateNames can be called before writing out a BAML record, and
        // ValidateEnums can be called later after the BAML record has been read.
 
 
        /// <summary>
        /// Validate the Name property.
        /// This will throw an exception if the property is an
        /// Name that does not follow the rules of only letters, digits and underscores in
        /// Name names.
        /// </summary>
        internal void ValidateNames(
            string   value,
            int      lineNumber,
            int      linePosition)
        {
            // set the linenumber and position
            _lineNumber = lineNumber;
            _linePosition = linePosition;
 
            if (value == string.Empty)
            {
                ThrowException(nameof(SR.ParserBadName), value);
            }
 
            if (MarkupExtensionParser.LooksLikeAMarkupExtension(value))
            {
                string message = SR.Format(SR.ParserBadUidOrNameME, value);
                message += " ";
                message += SR.Format(SR.ParserLineAndOffset,
                            lineNumber.ToString(CultureInfo.CurrentCulture),
                            linePosition.ToString(CultureInfo.CurrentCulture));
 
                XamlParseException parseException = new XamlParseException(message, lineNumber, linePosition);
 
                throw parseException;
            }
 
            if (!NameValidationHelper.IsValidIdentifierName(value))
            {
                ThrowException(nameof(SR.ParserBadName), value);
            }
        }
 
        /// <summary>
        /// Validate that if the type converter is
        /// for enums you can't pass numbers to it.
        /// </summary>
        internal void ValidateEnums(
            string        propName,
            Type          propType,
            string        attribValue)
        {
            if (propType.IsEnum && attribValue != string.Empty)
            {
                // Handle enum strings of the form "one, two, three".  Check that
                // each of the values does NOT start with a digit.  This doesn't
                // validate that the enum is correct, just that there are no digits
                // specified.
                bool lookingForComma = false;
                for (int i = 0; i < attribValue.Length; i++)
                {
                    if (!Char.IsWhiteSpace(attribValue[i]))
                    {
                        if (lookingForComma)
                        {
                            if (attribValue[i] == ',')
                            {
                                lookingForComma = false;
                            }
                        }
                        else if (Char.IsDigit(attribValue[i]))
                        {
                            ThrowException(nameof(SR.ParserNoDigitEnums), propName, attribValue);
                        }
                        else
                        {
                            lookingForComma = true;
                        }
                    }
                }
            }
        }
 
        /// <summary>
        /// Get cached member info for the property name.  This can be
        /// a PropertyInfo for the property or a MethodInfo for the static
        /// setter.  This does not work for EventInfo, so don't call it.
        /// </summary>
        /// <param name="owner">Type of the owner of the property </param>
        /// <param name="propName">Name of the property</param>
        /// <param name="onlyPropInfo">True if the caller wants the PropertyInfo for the
        ///     case where both a MethodInfo and propertyInfo are cached for this property
        /// </param>
        /// <param name="infoRecord">The attribute info record retrieved from
        ///     the map table, if one is found. </param>
        /// <remarks>
        /// There is only one scenario under which two memberInfo need to be
        /// cached for a given attribute. This is the case when there are both a
        /// Clr wrapper and static Settor for a given DP. In that case we cache
        /// an object array of two elements. Also the MethodInfo for the given DP
        /// will be discovered first by the XamlReaderHelper while the PropertyInfo
        /// will be discovered by the BamlRecordWriter.
        /// </remarks>
        private MemberInfo GetCachedMemberInfo(
               Type                    owner,
               string                  propName,
               bool                    onlyPropInfo,
           out BamlAttributeInfoRecord infoRecord)
        {
            infoRecord = null;
            if (MapTable != null)
            {
                string fullName = owner.IsGenericType ? $"{owner.Namespace}.{owner.Name}" : owner.FullName;
                object key = MapTable.GetAttributeInfoKey(fullName, propName);
                infoRecord = MapTable.GetHashTableData(key) as BamlAttributeInfoRecord;
 
                if (infoRecord != null)
                {
                    return infoRecord.GetPropertyMember(onlyPropInfo) as MemberInfo;
                }
            }
            return null;
        }
 
#if !PBTCOMPILER
        /// <summary>
        /// Add cached member info for the property name.
        /// </summary>
        private void AddCachedAttributeInfo(
               Type                    ownerType,
               BamlAttributeInfoRecord infoRecord)
        {
            if (MapTable != null)
            {
                object key = MapTable.GetAttributeInfoKey(ownerType.FullName, infoRecord.Name);
                MapTable.AddHashTableData(key, infoRecord);
            }
        }
 
        /// <summary>
        /// Helper function for getting Clr PropertyInfo on a type and updating the
        /// passed attribute info record.  Also update the property cache with this
        /// attribute information if it was not already present.
        /// </summary>
        /// <remarks>
        /// Note that the ObjectHashTable may contain
        /// a BamlAttributeInfoRecord from a previous parse for the same property.  If
        /// we find one in the hash table, use its property info instead of reflecting.
        /// </remarks>
        internal void UpdateClrPropertyInfo(
            Type currentParentType,
            BamlAttributeInfoRecord attribInfo)
        {
            Debug.Assert(null != attribInfo, "null attribInfo");
            Debug.Assert(null != currentParentType, "null currentParentType");
 
            bool isInternal = false;
            string propName = attribInfo.Name;
 
            BamlAttributeInfoRecord cachedInfoRecord;
            attribInfo.PropInfo = GetCachedMemberInfo(currentParentType, propName, true, out cachedInfoRecord)
                as PropertyInfo;
 
            if (attribInfo.PropInfo == null)
            {
                // If no cached property info, use the slow route of reflecting to get
                // the property info.
                attribInfo.PropInfo = PropertyInfoFromName(propName, currentParentType, !ReflectionHelper.IsPublicType(currentParentType), false, out isInternal);
                attribInfo.IsInternal = isInternal;
                if (attribInfo.PropInfo != null)
                {
                    // If we successfully find a property info via reflection, cache it.
                    if (cachedInfoRecord != null)
                    {
                        cachedInfoRecord.SetPropertyMember(attribInfo.PropInfo);
                        cachedInfoRecord.IsInternal = attribInfo.IsInternal;
                    }
                    else
                    {
                        AddCachedAttributeInfo(currentParentType, attribInfo);
                    }
                }
            }
            else
            {
                attribInfo.IsInternal = cachedInfoRecord.IsInternal;
            }
        }
 
        private void UpdateAttachedPropertyMethdodInfo(BamlAttributeInfoRecord attributeInfo, bool isSetter)
        {
            MethodInfo attachedPropertyInfo = null;
            Type propertyOwnerType = attributeInfo.OwnerType;
            Debug.Assert(propertyOwnerType != null);
            bool tryInternal = !ReflectionHelper.IsPublicType(propertyOwnerType);
            string propName = (isSetter ? "Set" : "Get") + attributeInfo.Name;
            BindingFlags flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy;
 
            // Check Set\GetFoo method presence
 
            try
            {
                if (!tryInternal)
                {
                    // first try public methods
                    attachedPropertyInfo = propertyOwnerType.GetMethod(propName, flags);
                }
 
                if (attachedPropertyInfo == null)
                {
                    // if public method not found, try non-public method next.
                    attachedPropertyInfo = propertyOwnerType.GetMethod(propName, flags | BindingFlags.NonPublic);
                }
            }
            catch (AmbiguousMatchException)
            {
            }
 
            int paramCount = isSetter ? 2 : 1;
            if (attachedPropertyInfo != null && attachedPropertyInfo.GetParameters().Length == paramCount)
            {
                // the MethodInfo has to be public or internal.
                Debug.Assert(attachedPropertyInfo.IsPublic ||
                                 attachedPropertyInfo.IsAssembly ||
                                 attachedPropertyInfo.IsFamilyOrAssembly);
 
                if (isSetter)
                {
                    attributeInfo.AttachedPropertySetter = attachedPropertyInfo;
                }
                else
                {
                    attributeInfo.AttachedPropertyGetter = attachedPropertyInfo;
                }
            }
        }
 
        internal void UpdateAttachedPropertySetter(BamlAttributeInfoRecord attributeInfo)
        {
            if (attributeInfo.AttachedPropertySetter == null)
            {
                UpdateAttachedPropertyMethdodInfo(attributeInfo, true);
            }
        }
 
        internal void UpdateAttachedPropertyGetter(BamlAttributeInfoRecord attributeInfo)
        {
            if (attributeInfo.AttachedPropertyGetter == null)
            {
                UpdateAttachedPropertyMethdodInfo(attributeInfo, false);
            }
        }
 
#endif
 
        /// <summary>
        /// Common helper method to resolve an xml XmlNamespace and LocalName to
        /// either a EventInfo or a PropertyInfo.
        /// </summary>
        /// <param name="isEvent">True if Event, False look for Property</param>
        /// <param name="owner">Type we should look for attribute on, can be null</param>
        /// <param name="xmlNamespace">XmlNamespace or the Attribute</param>
        /// <param name="localName">local Name of the Attribute</param>
        /// <param name="propName">Name of the resolved property or event</param>
        /// <returns>PropertyInfo or EventInfo for resolved property or event</returns>
        internal MemberInfo GetClrInfo(
                bool   isEvent,
                Type   owner,
                string xmlNamespace,
                string localName,
            ref string propName)
        {
            Debug.Assert(null != localName, "null localName");
            Debug.Assert(null != xmlNamespace, "null xmlNamespace");
 
            // adjust urtNamespace and localName if there are any periods in the localName.
            string globalClassName = null;
            int lastIndex = localName.LastIndexOf('.');
 
            if (-1 != lastIndex)
            {
                // If using .net then match against the class.
                globalClassName = localName.Substring(0, lastIndex);
                localName = localName.Substring(lastIndex+1);
            }
 
            return GetClrInfoForClass(isEvent, owner, xmlNamespace, localName, globalClassName, ref propName);
        }
 
#if PBTCOMPILER
        // Checks to see if a given event handler delegate type is accessible.
        static private bool IsAllowedEventDelegateType(Type delegateType)
        {
            if (!ReflectionHelper.IsPublicType(delegateType))
            {
                if (!ReflectionHelper.IsInternalType(delegateType) ||
                    !IsInternalAllowedOnType(delegateType))
                {
                    return false;
                }
            }
 
            return true;
        }
 
        // Checks to see if a given event's add method is accessible.
        // Checks for protected add methods as well if requested.
        private bool IsAllowedEvent(EventInfo ei, bool isProtectedAllowed)
        {
            MethodInfo mi = ei.GetAddMethod(true);
            return IsAllowedMethod(mi, isProtectedAllowed);
        }
 
        // Checks to see if a given property's set method is accessible.
        // Always checks for protected set methods as well.
        internal bool IsAllowedPropertySet(PropertyInfo pi)
        {
            MethodInfo mi = pi.GetSetMethod(true);
            return IsAllowedMethod(mi, true);
        }
 
        // Checks to see if a given property's get method is accessible.
        // Checks for protected get methods as well if requested.
        private bool IsAllowedPropertyGet(PropertyInfo pi, bool checkProtected)
        {
            MethodInfo mi = pi.GetGetMethod(true);
            return IsAllowedMethod(mi, checkProtected);
        }
 
        // Checks to see if a given property's get method is accessible.
        // Always checks for protected get methods as well.
        internal bool IsAllowedPropertyGet(PropertyInfo pi)
        {
            MethodInfo mi = pi.GetGetMethod(true);
            return IsAllowedMethod(mi, true);
        }
 
        // Checks to see if a given field member is accessible.
        private bool IsAllowedField(FieldInfo fi)
        {
            bool allowed = false;
 
            // No field, so not allowed
            if (fi != null)
            {
                // field is public -- always allow.
                allowed = fi.IsPublic;
                if (!allowed)
                {
                    // if not, try accessible internal fields.
                    // if the field from a base type, then it must be in the same assembly
                    // as the type from which it was reflected. If not, internals will not
                    // be allowed.
                    if (fi.ReflectedType.Assembly == fi.DeclaringType.Assembly)
                    {
                        // if reflected type is public, check to see if internals are allowed
                        // on that type (i.e local or friend). If not, the type has to be an
                        // internal allowed type due to the guaranteed central check in
                        // CreateTypeAndSerializer().
                        if (ReflectionHelper.IsPublicType(fi.ReflectedType))
                        {
                            allowed = IsInternalAllowedOnType(fi.ReflectedType);
                        }
                        else
                        {
                            allowed = true;
                        }
 
                        // Either ways, if reflected type is allowed only allow non-public
                        // fields that are internal.
                        allowed = allowed && (fi.IsAssembly || fi.IsFamilyOrAssembly);
                    }
                }
            }
 
            return allowed;
        }
 
        // Checks to see if a given methodInfo (for a property's get\set method
        // or an event's add method) is accessible.
        private bool IsAllowedMethod(MethodInfo mi, bool checkProtected)
        {
            bool allowed = false;
 
            // No method, so not allowed
            if (mi != null)
            {
                // method is public -- always allow.
                allowed = mi.IsPublic;
                if (!allowed)
                {
                    // method is not public.
                    // Next check to see if the mapper will allow looking for protected
                    // attributes. This will be the case if current methodInfo has been
                    // reflected off of the markup sub-classed root element, i.e one with
                    // an x:Class attribute, in which case IsProtectedAttributeAllowed will
                    // be true. So in this case allow protected if caller wishes for this
                    // by setting the checkProtected param to true.
                    if (checkProtected && IsProtectedAttributeAllowed)
                    {
                        // if so, allow protected or internal protected method.
                        allowed = mi.IsFamily || mi.IsFamilyOrAssembly;
                    }
 
                    if (!allowed)
                    {
                        // if not, try accessible internal methods.
                        // if the property or event inherits from a base type, then its
                        // accessor method must be in the same assembly as the type from
                        // which it was reflected. If not, internals will not be allowed.
                        if (mi.ReflectedType.Assembly == mi.DeclaringType.Assembly)
                        {
                            // if reflected type is public, check to see if internals are allowed
                            // on that type (i.e local or friend). If not, the type has to be an
                            // internal allowed type due to the guaranteed central check in
                            // CreateTypeAndSerializer().
                            if (ReflectionHelper.IsPublicType(mi.ReflectedType))
                            {
                                allowed = IsInternalAllowedOnType(mi.ReflectedType);
                            }
                            else
                            {
                                allowed = true;
                            }
 
                            // Either ways, if reflected type is allowed only allow non-public members
                            // that are internal.
                            allowed = allowed && (mi.IsAssembly || mi.IsFamilyOrAssembly);
                        }
                    }
                }
            }
 
            return allowed;
        }
#else
        // Checks to see if a given property's set method is public.
        // Used only in Xaml Load sceanrios.
        internal bool IsAllowedPropertySet(PropertyInfo pi)
        {
            MethodInfo mi = pi.GetSetMethod(true);
            return (mi != null && mi.IsPublic);
        }
 
        // Checks to see if a given property's get method is public.
        // Used only in Xaml Load sceanrios.
        internal bool IsAllowedPropertyGet(PropertyInfo pi)
        {
            MethodInfo mi = pi.GetGetMethod(true);
            return (mi != null && mi.IsPublic);
        }
 
        // Checks to see if a given property's set method is accessible.
        // Used only in compiled Baml Load sceanrios.
        static internal bool IsAllowedPropertySet(PropertyInfo pi, bool allowProtected, out bool isPublic)
        {
            MethodInfo mi = pi.GetSetMethod(true);
            bool isProtected = allowProtected && mi != null && mi.IsFamily;
            // return isPublic == true only if the property is public on a base declaring Type.
            // if the property is public on the reflected internal type itself, then we still
            // need to call the generated helper to set the property.
            isPublic = mi != null && mi.IsPublic && ReflectionHelper.IsPublicType(mi.DeclaringType);
            return (mi != null && (mi.IsPublic || mi.IsAssembly || mi.IsFamilyOrAssembly || isProtected));
        }
 
        // Checks to see if a given property's get method is accessible.
        // Used only in compiled Baml Load sceanrios.
        static private bool IsAllowedPropertyGet(PropertyInfo pi, bool allowProtected, out bool isPublic)
        {
            MethodInfo mi = pi.GetGetMethod(true);
            bool isProtected = allowProtected && mi != null && mi.IsFamily;
            // return isPublic == true only if the property is public on a base declaring Type.
            // if the property is public on the reflected internal type itself, then we still
            // need to call the generated helper to get the property.
            isPublic = mi != null && mi.IsPublic && ReflectionHelper.IsPublicType(mi.DeclaringType);
            return (mi != null && (mi.IsPublic || mi.IsAssembly || mi.IsFamilyOrAssembly || isProtected));
        }
 
        // Checks to see if a given event's add method is accessible.
        // Used only in compiled Baml Load sceanrios.
        static private bool IsAllowedEvent(EventInfo ei, bool allowProtected, out bool isPublic)
        {
            MethodInfo mi = ei.GetAddMethod(true);
            bool isProtected = allowProtected && mi != null && mi.IsFamily;
            // return isPublic == true only if the event is public on a base declaring Type.
            // if the event is public on the reflected internal type itself, then we still
            // need to call the generated helper to hook up the event.
            isPublic = mi != null && mi.IsPublic && ReflectionHelper.IsPublicType(mi.DeclaringType);
            return (mi != null && (mi.IsPublic || mi.IsAssembly || mi.IsFamilyOrAssembly || isProtected));
        }
#endif
 
        // Checks to see if a given event's add method is public.
        // Used in all (xaml load, xaml compile & compiled Baml Load sceanrios.
        static private bool IsPublicEvent(EventInfo ei)
        {
            MethodInfo mi = ei.GetAddMethod(true);
            return (mi != null && mi.IsPublic);
        }
 
#if !PBTCOMPILER
        /// <summary>
        /// Allows a sub-classed XamlTypeMapper called under Full Trust to participate
        /// in deciding if an internal type should be accessible.
        /// </summary>
        /// <param name="type">The internal type</param>
        /// <returns>
        /// When overriden, should return true if accessible, false if not.
        /// Returns false by default, if no one overrides.
        /// </returns>
        protected virtual bool AllowInternalType(Type type)
        {
            return false;
        }
 
        private bool IsInternalTypeAllowedInFullTrust(Type type)
        {
            bool isAllowed = false;
            // If the type is internal, then allow them to participate
            // in deciding if that internal type should be accessible.
            if (ReflectionHelper.IsInternalType(type))
            {
                isAllowed = AllowInternalType(type);
            }
 
            return isAllowed;
        }
#endif
 
        /// <summary>
        /// Common helper method to resolve an xml XmlNamespace and LocalName to
        /// either a EventInfo or a PropertyInfo.
        /// </summary>
        /// <param name="isEvent">True if Event, False look for Property</param>
        /// <param name="owner">Type we should look for attribute on, can be null</param>
        /// <param name="xmlNamespace">XmlNamespace or the Attribute</param>
        /// <param name="localName">local Name of the Attribute with no class</param>
        /// <param name="globalClassName">Class Name of the Attribute, or null if not present</param>
        /// <param name="propName">Name of the resolved property or event</param>
        /// <returns>PropertyInfo or EventInfo for resolved property or event</returns>
        internal MemberInfo GetClrInfoForClass (
                bool   isEvent,
                Type   owner,
                string xmlNamespace,
                string localName,
                string globalClassName,
            ref string propName)
        {
            MemberInfo mi = null;
#if PBTCOMPILER
            if (owner == null || ReflectionHelper.IsPublicType(owner))
            {
#endif
            // first, try normal lookup for public properties and events only.
                mi = GetClrInfoForClass(isEvent, owner, xmlNamespace, localName, globalClassName, false, ref propName);
#if PBTCOMPILER
            }
 
            if (mi == null && owner != null)
            {
                // if lookup on internal type or if public property or event lookup failed,
                // try internal ones as well, or protected if the type happens to be a
                // code-generated root.
                mi = GetClrInfoForClass(isEvent, owner, xmlNamespace, localName, globalClassName, true, ref propName);
            }
#endif
 
            return mi;
        }
 
        private MemberInfo GetClrInfoForClass(
                bool isEvent,
                Type owner,
                string xmlNamespace,
                string localName,
                string globalClassName,
                bool tryInternal,
            ref string propName)
        {
            bool isInternal = false;
            MemberInfo memberInfo = null;
            BindingFlags defaultBinding = BindingFlags.Public;
 
#if PBTCOMPILER
            if (tryInternal)
            {
                defaultBinding |= BindingFlags.NonPublic;
            }
#endif
 
            propName = null;
            ParameterInfo[] pis = null;
 
            // if this is a globalClass then resolve the type and then call the dpFromName
            if (null != globalClassName)
            {
                TypeAndSerializer typeAndSerializer =
                    GetTypeOnly(xmlNamespace, globalClassName);
 
                if (typeAndSerializer != null && typeAndSerializer.ObjectType != null)
                {
                    BamlAttributeInfoRecord infoRecord;
                    Type objectType = typeAndSerializer.ObjectType;
                    memberInfo = GetCachedMemberInfo(objectType, localName, false, out infoRecord);
 
                    if (memberInfo == null)
                    {
                        if (isEvent)
                        {
                            // See if attached event first
                            memberInfo = objectType.GetMethod($"Add{localName}Handler",
                                defaultBinding |
                                BindingFlags.Static |
                                BindingFlags.FlattenHierarchy);
 
                            // Make sure that we found a method of the right signature.
                            // Otherwise discard what you found.
                            if (memberInfo != null)
                            {
                                MethodInfo mi = memberInfo as MethodInfo;
                                if (mi != null)
                                {
                                    pis = mi.GetParameters();
                                    Type dependencyObjectType = KnownTypes.Types[(int)KnownElements.DependencyObject];
                                    if (pis == null || pis.Length != 2 || !dependencyObjectType.IsAssignableFrom(pis[0].ParameterType))
                                    {
                                        memberInfo = null;
                                    }
#if PBTCOMPILER
                                    if (tryInternal && memberInfo != null && !IsAllowedMethod(mi, false))
                                    {
                                        ThrowException(nameof(SR.ParserCantSetAttribute), "bubbling event", $"{objectType.Name}.{localName}", "Add Handler method");
                                    }
#endif
                                }
                            }
 
                            if (memberInfo == null)
                            {
                                // Not an attached event so try Clr event
                                memberInfo = objectType.GetEvent(localName,
                                    defaultBinding |
                                    BindingFlags.Instance |
                                    BindingFlags.FlattenHierarchy);
 
                                if (memberInfo != null)
                                {
                                    EventInfo ei = memberInfo as EventInfo;
#if PBTCOMPILER
                                    if (!IsAllowedEventDelegateType(ei.EventHandlerType))
#else
                                    if (!ReflectionHelper.IsPublicType(ei.EventHandlerType))
#endif
                                    {
                                        ThrowException(nameof(SR.ParserEventDelegateTypeNotAccessible), ei.EventHandlerType.FullName, $"{objectType.Name}.{localName}");
                                    }
 
#if PBTCOMPILER
                                    if (tryInternal)
                                    {
                                        // Check if the event add method accessor itself is accessible.
                                        // Also if this is a non-public event on a public type, it will
                                        // check to make sure that the public type is accessible\allowed.
                                        if (!IsAllowedEvent(ei, false))
                                        {
                                            ThrowException(nameof(SR.ParserCantSetAttribute), "event", $"{objectType.Name}.{localName}", "add");
                                        }
                                    }
                                    else
                                    {
#endif
                                        // Check if the event add method accessor itself is public.
                                        if (!IsPublicEvent(ei))
                                        {
#if PBTCOMPILER
                                            memberInfo = null;
#else
                                            ThrowException(nameof(SR.ParserCantSetAttribute), "event", $"{objectType.Name}.{localName}", "add");
#endif
                                        }
#if PBTCOMPILER
                                    }
#endif
                                }
                            }
                        }
                        else
                        {
                            // See if attached property first - start from a Setter
                            memberInfo = objectType.GetMethod($"Set{localName}",
                                defaultBinding |
                                BindingFlags.Static |
                                BindingFlags.FlattenHierarchy);
                            if (memberInfo != null && ((MethodInfo)memberInfo).GetParameters().Length != 2)
                            {
                                memberInfo = null;
                            }
                            // Try read-only case (Getter only)
                            if (memberInfo == null)
                            {
                                memberInfo = objectType.GetMethod($"Get{localName}",
                                    defaultBinding |
                                    BindingFlags.Static |
                                    BindingFlags.FlattenHierarchy);
                                if (memberInfo != null && ((MethodInfo)memberInfo).GetParameters().Length != 1)
                                {
                                    memberInfo = null;
                                }
                            }
 
#if PBTCOMPILER
                            if (tryInternal && memberInfo != null && !IsAllowedMethod(memberInfo as MethodInfo, false))
                            {
                                ThrowException(nameof(SR.ParserCantSetAttribute), "attached property", $"{objectType.Name}.{localName}", "Set method");
                            }
#endif
 
                            if (memberInfo == null)
                            {
                                // Not an attached property, so try clr property
                                memberInfo = PropertyInfoFromName(localName, objectType, tryInternal, true, out isInternal);
 
                                // If we've found a property info, then the owner had better
                                // be the same type as or a subclass of the objectType, or
                                // they are in different inheritance hierarchies.
                                if (memberInfo != null)
                                {
                                    if (owner != null &&
                                        !objectType.IsAssignableFrom(owner))
                                    {
                                        ThrowException(nameof(SR.ParserAttachedPropInheritError),
                                                       $"{objectType.Name}.{localName}",
                                                       owner.Name);
                                    }
                                }
                            }
 
                            if (null != memberInfo)
                            {
                                if (infoRecord != null)
                                {
#if !PBTCOMPILER
                                    // DP's aren't present in the PBT case
                                    if (infoRecord.DP == null)
                                    {
                                        infoRecord.DP = MapTable.GetDependencyProperty(infoRecord);
                                    }
#endif
                                    infoRecord.SetPropertyMember(memberInfo);
                                }
                            }
                        }
                    }
                }
            }
            else if (null != owner)
            {
                Type baseType = owner;
 
                // See if the owner knows about this class.
                // Look for a parent type until we find a match or fail.
                if (null != baseType)
                {
                    BamlAttributeInfoRecord infoRecord;
                    memberInfo = GetCachedMemberInfo(baseType, localName, false, out infoRecord);
 
                    if (memberInfo == null)
                    {
                        if (isEvent)
                        {
                            // See if attached event first
                            memberInfo = baseType.GetMethod($"Add{localName}Handler",
                                defaultBinding | BindingFlags.Static | BindingFlags.FlattenHierarchy);
 
                            // Make sure that we found a method of the right signature.
                            // Otherwise discard what you found.
                            if (memberInfo != null)
                            {
                                MethodInfo mi = memberInfo as MethodInfo;
                                if (mi != null)
                                {
                                    pis = mi.GetParameters();
                                    Type dependencyObjectType = KnownTypes.Types[(int)KnownElements.DependencyObject];
                                    if (pis == null || pis.Length != 2 || !dependencyObjectType.IsAssignableFrom(pis[0].ParameterType))
                                    {
                                        memberInfo = null;
                                    }
#if PBTCOMPILER
                                    if (tryInternal && memberInfo != null && !IsAllowedMethod(mi, true))
                                    {
                                        ThrowException(nameof(SR.ParserCantSetAttribute), "bubbling event", $"{owner.Name}.{localName}", "Add Handler method");
                                    }
#endif
                                }
                            }
 
                            if (memberInfo == null)
                            {
                                // Not an attached event, so try for a clr event.
                                memberInfo = baseType.GetEvent(localName,
                                    BindingFlags.Instance | BindingFlags.FlattenHierarchy | defaultBinding);
 
                                if (memberInfo != null)
                                {
                                    EventInfo ei = memberInfo as EventInfo;
#if PBTCOMPILER
                                    if (!IsAllowedEventDelegateType(ei.EventHandlerType))
#else
                                    if (!ReflectionHelper.IsPublicType(ei.EventHandlerType))
#endif
                                    {
                                        ThrowException(nameof(SR.ParserEventDelegateTypeNotAccessible), ei.EventHandlerType.FullName, $"{owner.Name}.{localName}");
                                    }
 
#if PBTCOMPILER
                                    if (tryInternal)
                                    {
                                        // Check if the event add method accessor itself is accessible.
                                        // Also if this is a non-public event on a public type, it will
                                        // not check to make sure that the public type is accessible\allowed
                                        // since that would have all ready been done in the caller of this fucntion.
                                        if (!IsAllowedEvent(ei, true))
                                        {
                                            ThrowException(nameof(SR.ParserCantSetAttribute), "event", $"{owner.Name}.{localName}", "add");
                                        }
                                    }
                                    else
                                    {
#endif
                                        // check if the event add method accessor itself is public.
                                        if (!IsPublicEvent(ei))
                                        {
#if PBTCOMPILER
                                            memberInfo = null;
#else
                                            ThrowException(nameof(SR.ParserCantSetAttribute), "event", $"{owner.Name}.{localName}", "add");
#endif
                                        }
#if PBTCOMPILER
                                    }
#endif
                                }
                            }
                        }
                        else
                        {
                            // See if attached property first - start from a Setter
                            memberInfo = baseType.GetMethod($"Set{localName}",
                                defaultBinding |
                                BindingFlags.Static |
                                BindingFlags.FlattenHierarchy);
                            if (memberInfo != null && ((MethodInfo)memberInfo).GetParameters().Length != 2)
                            {
                                memberInfo = null;
                            }
                            // Try read-only case (Getter only)
                            if (memberInfo == null)
                            {
                                memberInfo = baseType.GetMethod($"Get{localName}",
                                    defaultBinding |
                                    BindingFlags.Static |
                                    BindingFlags.FlattenHierarchy);
                                if (memberInfo != null && ((MethodInfo)memberInfo).GetParameters().Length != 1)
                                {
                                    memberInfo = null;
                                }
                            }
 
#if PBTCOMPILER
                            if (tryInternal && memberInfo != null && !IsAllowedMethod(memberInfo as MethodInfo, true))
                            {
                                ThrowException(nameof(SR.ParserCantSetAttribute), "attached property", $"{owner.Name}.{localName}", "Set method");
                            }
#endif
 
                            if (memberInfo == null)
                            {
                                // Not an attached property, so try for a clr property.
                                memberInfo = PropertyInfoFromName(localName, baseType, tryInternal, true, out isInternal);
                            }
 
                            if (null != memberInfo)
                            {
                                if (infoRecord != null)
                                {
#if !PBTCOMPILER
                                    // DP's aren't present in the PBT case
                                    if (infoRecord.DP == null)
                                    {
                                        infoRecord.DP = MapTable.GetDependencyProperty(infoRecord);
                                    }
#endif
                                    infoRecord.SetPropertyMember(memberInfo);
                                }
                            }
                        }
                    }
                }
            }
 
            if (null != memberInfo)
            {
                propName = localName;
            }
 
            return memberInfo;
        }
 
#if !PBTCOMPILER
        /// <summary>
        /// Helper method to get an event on an owner, walking up the class hierarchy
        /// when doing so
        /// </summary>
        /// <param name="owner">Type we should look for the event on</param>
        /// <param name="eventName">Then name of the handler of the event</param>
        /// <returns>EventInfo for resolved event</returns>
        internal EventInfo GetClrEventInfo(
            Type   owner,
            string eventName)
        {
            Debug.Assert(null != eventName, "null eventName");
            Debug.Assert(null != owner, "null owner");
 
            EventInfo eventInfo = null;
 
            // Look up the parent chain until we find a match or fail by
            // going off the top of the chain.
            while (owner != null)
            {
                eventInfo = owner.GetEvent(eventName, BindingFlags.Instance | BindingFlags.Public);
                if (eventInfo != null)
                {
                    break;
                }
 
                owner = GetCachedBaseType(owner);
            }
 
            return eventInfo;
        }
 
        /// <summary>
        /// Helper method to resolve an xml namespace and localName to
        /// either a RoutedEvent or a DependencyProperty.  If they are not present,
        /// still resolve using a guess at the valid setter name to look for.
        /// </summary>
        /// <remarks>
        ///  Note that this will not resolve clr properties.  Call GetClrInfo to do that.
        /// </remarks>
        /// <param name="isEvent">True if Event, False look for Property</param>
        /// <param name="owner">Type we should look for attribute on, can be null</param>
        /// <param name="xmlNamespace">XmlNamespace or the Attribute</param>
        /// <param name="localName">local Name of the Attribute</param>
        /// <param name="baseType">Base type the object was found on</param>
        /// <param name="dynamicObjectName">registered name of the Object on the type.</param>
        /// <returns>resolved object, which can be a RoutedEvent, a DependencyProperty
        ///          or the MethodInfo for the event or property setter</returns>
        internal object GetDependencyObject(
                bool       isEvent,
                Type       owner,
                string     xmlNamespace,
                string     localName,
            ref Type       baseType,
            ref string     dynamicObjectName)
        {
            Debug.Assert(null != localName, "null localName");
            Debug.Assert(null != xmlNamespace, "null xmlNamespace");
 
            object memInfo = null;
            string globalClassName = null;
 
            dynamicObjectName = null;
 
            // Extract the class name if there are any periods in the localName.
            int lastIndex = localName.LastIndexOf('.');
            if (-1 != lastIndex)
            {
                // if using .net then match against the class.
                globalClassName = localName.Substring(0,lastIndex);
                localName = localName.Substring(lastIndex+1);
            }
 
            // If this is a globalClassName then resolve the type and then call
            // DependencyProperty.FromName.
            if (null != globalClassName)
            {
                TypeAndSerializer typeAndSerializer =
                    GetTypeOnly(xmlNamespace,globalClassName);
 
                if (typeAndSerializer != null && typeAndSerializer.ObjectType != null)
                {
                    baseType = typeAndSerializer.ObjectType;
                    if (isEvent)
                    {
                        memInfo = RoutedEventFromName(localName,baseType);
                    }
                    else
                    {
                        memInfo = DependencyProperty.FromName(localName, baseType);
                    }
 
                    if (null != memInfo)
                    {
                        Debug.Assert(null != baseType, "baseType not set");
                        dynamicObjectName = localName;
                    }
                }
            }
            else
            {
                NamespaceMapEntry[] namespaceMaps = GetNamespaceMapEntries(xmlNamespace);
 
                if (null == namespaceMaps)
                {
                    return null;
                }
 
                baseType = owner;
 
                // See if the owner knows about this class.
                // Look for a parent type with any namespace matching the property
                while (null != baseType)
                {
                    bool foundNamespaceMatch = false;
 
                    // Look at each namespace for a match with this baseType
                    for (int count = 0;
                         count < namespaceMaps.Length && !foundNamespaceMatch;
                         count ++)
                    {
                        NamespaceMapEntry namespaceMap = namespaceMaps[count];
 
                        // see if the urtNamespace in the namespace map is valid
                        // for the type we are trying to apply
                        if (namespaceMap.ClrNamespace == GetCachedNamespace(baseType))
                        {
                            foundNamespaceMatch = true;
                        }
                    }
 
                    if (foundNamespaceMatch)
                    {
                        // For 'normal' properties and events that are not prefixed by
                        // a class name, only attempt to get dependency IDs and Events.
                        // The caller should use GetClrInfo to get CLR properties for
                        // 'normal' properties and events if this attempt fails.
                        if (isEvent)
                        {
                            memInfo = RoutedEventFromName(localName,baseType);
                        }
                        else
                        {
                            memInfo = DependencyProperty.FromName(localName, baseType);
                        }
                    }
 
                    // Only do one loop for events, since all base classes are checked in
                    // a single operation.  For properties, loop through the base classes here.
                    if (null != memInfo || isEvent)
                    {
                        // for assembly and typeName use the original, not the base
                        // type we found it on.
                        dynamicObjectName = localName;
                        break;
                    }
                    else
                    {
                        baseType = GetCachedBaseType(baseType);
                    }
                }
            }
 
            return memInfo;
        }
 
 
         ///<summary>
        /// Returns a DependencyProperty given a local name and an xml namespace
        ///</summary>
        ///<param name="localName">
        /// The property name
        ///</param>
        ///<param name="xmlNamespace">
        /// Xml namespace associated with name
        ///</param>
        ///<param name="ownerType">
        /// The Type where this DP was registered.
        ///</param>
        ///<returns>
        /// Returns a DependencyProperty the attached property
        ///</returns>
        internal DependencyProperty DependencyPropertyFromName(
                string localName,
                string xmlNamespace,
            ref Type   ownerType)
         {
             Debug.Assert(null != localName, "null localName");
             Debug.Assert(null != xmlNamespace, "null xmlNamespace");
 
            // Adjust localName if there are any periods that indicate a global class.  Use
            // this class name as the owner type and return it.  Otherwise just use the
            // passed name and owner.
            int lastIndex = localName.LastIndexOf('.');
            if (-1 != lastIndex)
            {
                string globalClassName = localName.Substring(0,lastIndex);
                localName = localName.Substring(lastIndex+1);
                TypeAndSerializer typeAndSerializer =
                    GetTypeOnly(xmlNamespace, globalClassName);
                if (typeAndSerializer == null || typeAndSerializer.ObjectType == null)
                {
                    ThrowException(nameof(SR.ParserNoType), globalClassName);
                }
                ownerType = typeAndSerializer.ObjectType;
            }
 
            if(null == ownerType)
            {
                throw new ArgumentNullException( "ownerType" );
            }
 
            return DependencyProperty.FromName(localName, ownerType);
        }
 
#endif
 
        /// <summary>
        /// Return the property that has an attached XmlLang attribute.  This identifies this
        /// property as being the one to receive xml:lang attribute values when parsing, or
        /// the holder of the CultureInfo related string.  The XamlTypeMapper caches this
        /// along with the TypeAndSerializer information for fast retrieval.
        /// </summary>
        internal PropertyInfo GetXmlLangProperty(
                string    xmlNamespace,     // xml namespace for the type
                string    localName)        // local name of the type without any '.'
        {
            TypeAndSerializer typeAndSerializer = GetTypeOnly(xmlNamespace, localName);
 
            if (typeAndSerializer == null || typeAndSerializer.ObjectType == null)
            {
                return null;
            }
 
            if (typeAndSerializer.XmlLangProperty == null)
            {
                BamlAssemblyInfoRecord bairPF = MapTable.GetAssemblyInfoFromId(-1);
 
                if (typeAndSerializer.ObjectType.Assembly == bairPF.Assembly)
                {
                    if (KnownTypes.Types[(int)KnownElements.FrameworkElement].IsAssignableFrom(typeAndSerializer.ObjectType) ||
                        KnownTypes.Types[(int)KnownElements.FrameworkContentElement].IsAssignableFrom(typeAndSerializer.ObjectType))
                    {
                        typeAndSerializer.XmlLangProperty = (KnownTypes.Types[(int)KnownElements.FrameworkElement]).GetProperty("Language",
                            BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
                    }
                }
                else
                {
                    string xmlLangPropertyName = null;
                    bool   xmlLangPropertyFound = false;
 
#if !PBTCOMPILER
                    AttributeCollection attributes = TypeDescriptor.GetAttributes(typeAndSerializer.ObjectType);
 
                    if (attributes != null)
                    {
                        XmlLangPropertyAttribute xlpa = attributes[typeof(XmlLangPropertyAttribute)] as XmlLangPropertyAttribute;
                        if (xlpa != null)
                        {
                            xmlLangPropertyFound = true;
                            xmlLangPropertyName = xlpa.Name;
                        }
                    }
#else
                    Type typeValue = null;
                    xmlLangPropertyName = ReflectionHelper.GetCustomAttributeData(typeAndSerializer.ObjectType,
                                                                                  KnownTypes.Types[(int)KnownElements.XmlLangPropertyAttribute],
                                                                                  false,
                                                                              ref xmlLangPropertyFound,
                                                                              out typeValue);
#endif
 
                    if ( xmlLangPropertyFound )
                    {
                        if( xmlLangPropertyName != null && xmlLangPropertyName.Length > 0)
                        {
                            typeAndSerializer.XmlLangProperty = typeAndSerializer.ObjectType.GetProperty(
                                xmlLangPropertyName,
                                BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
                        }
 
                        if( typeAndSerializer.XmlLangProperty == null )
                        {
                            // Either the given name could not be found, or there
                            //  was no name specified at all.  (null or empty string.)
                            // The latter case may get a special meaning in the future,
                            //  but for now they're all errors.
                            ThrowException(nameof(SR.ParserXmlLangPropertyValueInvalid));
                        }
                    }
                }
            }
 
            return typeAndSerializer.XmlLangProperty;
        }
 
        ///<summary>
        /// Returns a PropertyInfo from an attribute name, given the ownerType of
        /// the property.
        ///</summary>
        ///<param name="localName">
        /// The attribute name
        ///</param>
        ///<param name="ownerType">
        /// The Type that owns the attribute
        ///</param>
        ///<param name="tryInternal">
        /// Indicates if this function should search for non-public properties as well
        ///</param>
        ///<param name="tryPublicOnly">
        /// Indicates if this function should search for public properties only, regardless
        /// of tryInternal as is the case in XamlLoad sceanrios.
        ///</param>
        ///<param name="isInternal">
        /// Indicates if this fucntion actually found a non-public property
        ///</param>
        ///<returns>
        /// Returns a PropertyInfo for the property
        ///</returns>
        private PropertyInfo PropertyInfoFromName(
            string localName,
            Type   ownerType,
            bool tryInternal,
            bool tryPublicOnly,
            out bool isInternal)
        {
            PropertyInfo info = null;
            isInternal = false;
            TypeInformationCacheData typeInfo = GetCachedInformationForType(ownerType);
            Debug.Assert(typeInfo != null, "Must have cached type info at this point");
            PropertyAndType propAndType = typeInfo.GetPropertyAndType(localName);
 
            // peterost - This is a TEMPORARY workaround to
            //    properties that have been overridden in some classes using the
            //    "new" operator.  This should be removed when properties such as
            //    Window.Width and ColumnDefintion.Width are rationalized.
            if (propAndType == null || !propAndType.PropInfoSet)
            {
                try
                {
                    BindingFlags flags = BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.Public;
#if PBTCOMPILER
                    if (tryInternal)
                    {
                        flags |= BindingFlags.NonPublic;
                    }
                    info = ownerType.GetProperty(localName, flags);
#else
                    if (!tryInternal)
                    {
                        info = ownerType.GetProperty(localName, flags);
                    }
 
                    // Xaml load scenarios should not look for internals - tryPublicOnly == true
                    // If the above load failed then try again looking at internals, unless
                    // tryPublicOnly tells us not to do that.
                    if (info == null && !tryPublicOnly)
                    {
                        info = ownerType.GetProperty(localName, flags | BindingFlags.NonPublic);
                        if (info != null)
                        {
                            isInternal = true;
                        }
                    }
#endif
                }
                catch (AmbiguousMatchException)
                {
                    PropertyInfo[] infos = ownerType.GetProperties(
                                  BindingFlags.Instance | BindingFlags.Public);
                    for (int i = 0; i < infos.Length; i++)
                    {
                        if (infos[i].Name == localName)
                        {
                            info = infos[i];
                            break;
                        }
                    }
                }
#if PBTCOMPILER
                if (tryInternal || info != null)
                {
#endif
                    typeInfo.SetPropertyAndType(localName, info, ownerType, isInternal);
#if PBTCOMPILER
                }
#endif
            }
            else
            {
                info = propAndType.PropInfo;
                isInternal = propAndType.IsInternal;
            }
 
            return info;
        }
 
#if !PBTCOMPILER
 
        ///<summary>
        /// Returns a RoutedEvent from an attribute name
        ///</summary>
        ///<param name="localName">
        /// The attribute name
        ///</param>
        ///<param name="ownerType">
        /// The Type that owns the attribute
        ///</param>
        ///<returns>
        /// Returns a RoutedEvent for the name
        ///</returns>
        internal RoutedEvent RoutedEventFromName(
            string localName,
            Type   ownerType)
        {
            RoutedEvent Event = null;
            Type currentType = ownerType;
 
            // Force load the Statics by walking up the hierarchy and running class constructors
            while (null != currentType)
            {
                RuntimeHelpers.RunClassConstructor(currentType.TypeHandle);
                currentType = GetCachedBaseType(currentType);
            }
 
            // EventManager takes care of going up the hierarchy, so we don't need to loop here
            // to do it.  Just do one call.
            Event =  EventManager.GetRoutedEventFromName(localName,ownerType);
 
            return Event;
       }
#endif
 
        /// <summary>
        /// Given an object that is either a PropertyInfo, MethodInfo for the static
        /// setter, or DependencyProperty, return the type of the property.  This assumes
        /// the Avalon rule that a DependencyProperty has a static setter where the
        /// second parameter gives the type of the property.
        /// </summary>
        internal static Type GetPropertyType(object propertyMember)
        {
            Type propertyType;
            bool propertyCanWrite;
            GetPropertyType(propertyMember, out propertyType, out propertyCanWrite);
 
            return propertyType;
        }
 
        /// <summary>
        /// Given an object that is either a PropertyInfo, MethodInfo for the static
        /// setter, or DependencyProperty, return the type of the property.  This assumes
        /// the Avalon rule that a DependencyProperty has a static setter where the
        /// second parameter gives the type of the property.
        /// </summary>
        internal static void GetPropertyType(
            object propertyMember,
        out Type   propertyType,
        out bool   propertyCanWrite)
        {
#if !PBTCOMPILER
            DependencyProperty dp = propertyMember as DependencyProperty;
            if (dp != null)
            {
                propertyType = dp.PropertyType;
                propertyCanWrite = !dp.ReadOnly;
            }
            else
            {
#endif
                PropertyInfo propertyInfo = propertyMember as PropertyInfo;
                if (propertyInfo != null)
                {
                    propertyType = propertyInfo.PropertyType;
                    propertyCanWrite = propertyInfo.CanWrite;
                }
                else
                {
                    MethodInfo methodInfo = propertyMember as MethodInfo;
                    if (methodInfo != null)
                    {
                        ParameterInfo[] parameters = methodInfo.GetParameters();
                        propertyType = parameters.Length == 1 ? methodInfo.ReturnType : parameters[1].ParameterType;
                        propertyCanWrite = parameters.Length == 1 ? false : true;
                    }
                    else
                    {
                        // If its not a propertyinfo, methodinfo, or dependencyproperty,
                        // all we know is that it must be an object...
                        propertyType = typeof(object);
                        propertyCanWrite = false;
                    }
                }
#if !PBTCOMPILER
            }
#endif
        }
 
 
        /// <summary>
        /// Given an object that is either a PropertyInfo, MethodInfo for the static
        /// setter, or DependencyProperty, return the name of the property.  This assumes
        /// the Avalon rule that a DependencyProperty has a static getter "Get" + name.
        /// </summary>
        internal static string GetPropertyName(object propertyMember)
        {
#if !PBTCOMPILER
            DependencyProperty dp = propertyMember as DependencyProperty;
            if (dp != null)
            {
                return dp.Name;
            }
#endif
 
            PropertyInfo propertyInfo = propertyMember as PropertyInfo;
            if (propertyInfo != null)
            {
                return propertyInfo.Name;
            }
            else
            {
                MethodInfo methodInfo = propertyMember as MethodInfo;
                if (methodInfo != null)
                {
                    return methodInfo.Name.Substring("Get".Length);
                }
            }
 
            return null;
        }
 
        /// <summary>
        /// Given an object that is either a PropertyInfo, MethodInfo for the static
        /// setter, or DependencyProperty, return the type of the object that declares
        /// or owns this property.
        /// </summary>
        internal static Type GetDeclaringType(object propertyMember)
        {
            Type validType = null;
            MemberInfo memInfo = propertyMember as MemberInfo;
            if (memInfo != null)
            {
                validType = memInfo.DeclaringType;
            }
            else
            {
#if !PBTCOMPILER
                Debug.Assert( propertyMember is DependencyProperty);
                validType = ((DependencyProperty)propertyMember).OwnerType;
#endif
            }
 
            return validType;
        }
#endregion Properties
 
#region Types
 
#if !PBTCOMPILER
        /// <summary>
        ///  Return the type that corresponds to typeName, given that the type is
        ///  located as a subelement or property on the passed element.
        /// </summary>
        /// <param name="typeName">
        ///   The full xaml name of a type, including an xml namespace prefix, if needed.
        ///   The name is of the form prefix:typename, such as MyNs:MyNewButton
        /// </param>
        /// <param name="element">
        ///   A DependencyObject that is logical parent for the type to be resolved.  This
        ///   is required because it is this element (or its ancestors) that contains
        ///   namespace mapping data that is needed to resolve the typeName.
        /// </param>
        /// <returns>
        ///  The resolved clr type.  Null if not found
        /// </returns>
        internal static Type GetTypeFromName(string typeName, DependencyObject element)
        {
            if (element == null)
            {
                throw new ArgumentNullException( "element" );
            }
            if (typeName == null)
            {
                throw new ArgumentNullException( "typeName" );
            }
 
            // Now map the prefix to an xml namespace uri
            int colonIndex = typeName.IndexOf(':');
            string prefix = string.Empty;
            if (colonIndex > 0)
            {
                prefix = typeName.Substring(0, colonIndex);
                typeName = typeName.Substring(colonIndex+1, typeName.Length-colonIndex-1);
            }
 
            // First, get the xmlns dictionary to map prefixes to xml namespace uris
            XmlnsDictionary prefixDictionary = element.GetValue(XmlAttributeProperties.XmlnsDictionaryProperty)
                                               as XmlnsDictionary;
 
            object xmlNamespaceObject = (prefixDictionary != null) ? prefixDictionary[prefix] : null;
 
            // Then get the list of NamespaceMapEntry objects that maps the xml namespace uri to one
            // or more clr namespace / assembly pairs.  This should be stored on the root element
            // of the tree.
            Hashtable namespaceMaps = element.GetValue(XmlAttributeProperties.XmlNamespaceMapsProperty)
                                               as Hashtable;
 
            NamespaceMapEntry[] namespaces = (namespaceMaps != null && xmlNamespaceObject != null) ? namespaceMaps[xmlNamespaceObject] as NamespaceMapEntry[] : null;
 
            if (namespaces == null)
            {
                //           If the namespace prefix is empty, we may not have
                //           loaded the default namespace.  Get this from
                //           the token reader.  NOTE:  This is a temporary stopgap
                //           until we figure out exact requirements for namespace
                //           resolution as it applies to styles, etc.
                if (prefix == string.Empty)
                {
                    List<ClrNamespaceAssemblyPair> namespaceAssemblyPair = GetClrNamespacePairFromCache(XamlReaderHelper.DefaultNamespaceURI);
                    foreach (ClrNamespaceAssemblyPair usd in namespaceAssemblyPair)
                    {
                        if (usd.AssemblyName != null)
                        {
                            Assembly assy = ReflectionHelper.LoadAssembly(usd.AssemblyName, null);
                            if (assy != null)
                            {
                                string fullTypeName = $"{usd.ClrNamespace}.{typeName}";
                                Type t = assy.GetType(fullTypeName);
                                if (t != null)
                                    return t;
                            }
                        }
                    }
                }
 
                // Stopgap didn't work, so fail now.
                return null;
            }
 
            // Check all the clr namespace / assembly pairs to see if there is a type
            // that matches the passed short name.  Return it if found.
            for (int i = 0; i < namespaces.Length; i++)
            {
                Assembly assy = namespaces[i].Assembly;
                if (assy != null)
                {
                    string fullTypeName = $"{namespaces[i].ClrNamespace}.{typeName}";
                    Type t = assy.GetType(fullTypeName);
                    if (t != null)
                    {
                        return t;
                    }
                }
            }
 
            // Didn't find a match, so return null.
            return null;
       }
#endif
 
        // Given a qualified member Name, returns its declaring Type and its name as a string.
        internal Type GetTargetTypeAndMember(string valueParam,
                                             ParserContext context,
                                             bool isTypeExpected,
                                         out string memberName)
        {
            string typeName = valueParam;
            string prefix = String.Empty;
            int typeIndex = typeName.IndexOf(':');
            if (typeIndex >= 0)
            {
                prefix = typeName.Substring(0, typeIndex);
                typeName = typeName.Substring(typeIndex + 1);
            }
 
            memberName = null;
            Type targetType = null;
 
            typeIndex = typeName.LastIndexOf('.');
            if (typeIndex >= 0)
            {
                memberName = typeName.Substring(typeIndex + 1);
                typeName = typeName.Substring(0, typeIndex);
                string namespaceUri = context.XmlnsDictionary[prefix];
                TypeAndSerializer tas = GetTypeOnly(namespaceUri, typeName);
                if (tas != null)
                {
                    targetType = tas.ObjectType;
                }
                if (targetType == null)
                {
                    ThrowException(nameof(SR.ParserNoType), typeName);
                }
            }
            else if (!isTypeExpected && prefix.Length == 0)
            {
                // A Type may not be expected for e.g. for TemplateBinding param
                // values. In this case there must also not be a prefix. If there
                // is one it will just point to a namespace and not a Type.
                memberName = typeName;
            }
            else
            {
                // A type was expected but we didn't find one. So throw.
                ThrowException(nameof(SR.ParserBadMemberReference), valueParam);
            }
 
 
            return targetType;
        }
 
        // Given a qualified member Name, returns its declaring Type and its name as a string.
        internal Type GetDependencyPropertyOwnerAndName(string memberValue,
                                                        ParserContext context,
                                                        Type defaultTargetType,
                                                    out string memberName)
        {
            Type targetType = GetTargetTypeAndMember(memberValue, context, false, out memberName);
            if (targetType == null)
            {
                targetType = defaultTargetType;
                if (targetType == null)
                {
                    // if there was also no default target type then throw.
                    ThrowException(nameof(SR.ParserBadMemberReference), memberValue);
                }
            }
 
            Debug.Assert(memberName != null);
            string fieldName = $"{memberName}Property";
            MemberInfo memberInfo = GetStaticMemberInfo(targetType, fieldName, true);
            Debug.Assert(memberInfo != null);
 
            // Need to get the actual type that declares the DP in order to
            // correctly find a possible hit in the KnownProperties table.
            if (memberInfo.DeclaringType != targetType)
            {
                targetType = memberInfo.DeclaringType;
            }
 
            return targetType;
        }
 
        // Gets the PropertyInfo or FieldInfo of a member.
        internal MemberInfo GetStaticMemberInfo(Type targetType, string memberName, bool fieldInfoOnly)
        {
            Debug.Assert(targetType != null);
            // first try public members only.
            MemberInfo mi = GetStaticMemberInfo(targetType, memberName, fieldInfoOnly, false);
 
#if PBTCOMPILER
            if (mi == null)
            {
                // If not found, then try non-public members next.
                mi = GetStaticMemberInfo(targetType, memberName, fieldInfoOnly, true);
                if (mi != null)
                {
                    // if found, check access levels to see if it should really be allowed.
                    bool isAllowed = false;
                    PropertyInfo pi = mi as PropertyInfo;
                    if (pi != null)
                    {
                        isAllowed = IsAllowedPropertyGet(pi, false);
                    }
                    else
                    {
                        isAllowed = IsAllowedField(mi as FieldInfo);
                    }
 
                    if (!isAllowed)
                    {
                        ThrowException(nameof(SR.ParserStaticMemberNotAllowed), memberName, targetType.Name);
                    }
                }
            }
#endif
            if (mi == null)
            {
                ThrowException(nameof(SR.ParserInvalidStaticMember), memberName, targetType.Name);
            }
 
            return mi;
        }
 
        private MemberInfo GetStaticMemberInfo(Type targetType, string memberName, bool fieldInfoOnly, bool tryInternal)
        {
            MemberInfo memberInfo = null;
            BindingFlags bf = BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Static;
 
            if (tryInternal)
            {
                bf |= BindingFlags.NonPublic;
            }
 
            if (!fieldInfoOnly)
            {
                memberInfo = targetType.GetProperty(memberName, bf);
            }
 
            if (memberInfo == null)
            {
                memberInfo = targetType.GetField(memberName, bf);
            }
 
            return memberInfo;
        }
 
        /// <summary>
        /// Get the Type that type corresponds to a localName in
        /// the given namespace.  Note that localName can be of the form classname.typename,
        /// and can not include a namespace prefix.
        /// </summary>
        /// <remarks>
        /// Return the actual type and the serializer for that type as a
        /// TypeAndSerializer object from the cache.  Note that in this call
        /// the Serializer information may not be present if a new TypeAndSerializer
        /// instance is created.  Be sure to check the IsSerializerTypeSet flag.
        /// </remarks>
        internal TypeAndSerializer GetTypeOnly (
                string    xmlNamespace,     // xml namespace for the type
                string    localName)        // local name of the type without any '.'
        {
            Debug.Assert(null != xmlNamespace,"null value passed for xmlNamespace");
            Debug.Assert(null != localName,"null value passed for localName");
 
            // check if object is in the Hash.
            String hashString = $"{xmlNamespace}:{localName}";
 
            TypeAndSerializer typeAndSerializer =
                 _typeLookupFromXmlHashtable[hashString] as TypeAndSerializer;
 
            if (null == typeAndSerializer)
            {
                if (!_typeLookupFromXmlHashtable.Contains(hashString))
                {
                    typeAndSerializer = CreateTypeAndSerializer(xmlNamespace, localName);
                    _typeLookupFromXmlHashtable[hashString] = typeAndSerializer;
                }
            }
 
            return typeAndSerializer;
        }
 
        /// <summary>
        /// Get the Type and serializer for that type corresponding to a localName in
        /// the given namespace.  Note that localName can be of the form classname.typename,
        /// and can not include a namespace prefix.
        /// </summary>
        /// <remarks>
        /// Return the actual type and the serializer for that type as a
        /// TypeAndSerializer object from the cache.  If there is no
        /// serializer defined, as is the case for clr objects, then null is set
        /// for the SerializerType in the returned TypeAndSerializer. Also if this type is
        /// associated with a property we will check for serializer attributes on the property first.
        /// If no matching attribute is found for the property we resort to search for the attribute on the given type.
        /// </remarks>
        internal TypeAndSerializer GetTypeAndSerializer (
                string    xmlNamespace,     // xml namespace for the type
                string    localName,        // local name of the type without any '.'
                object    dpOrPiorMi)       // property associated with the type
        {
            Debug.Assert(null != xmlNamespace,"null value passed for xmlNamespace");
            Debug.Assert(null != localName,"null value passed for localName");
 
            // check if object is in the Hash.
            String hashString = $"{xmlNamespace}:{localName}";
 
            TypeAndSerializer typeAndSerializer =
                _typeLookupFromXmlHashtable[hashString] as TypeAndSerializer;
 
            if (null == typeAndSerializer)
            {
                if (!_typeLookupFromXmlHashtable.Contains(hashString))
                {
                    typeAndSerializer = CreateTypeAndSerializer(xmlNamespace, localName);
                    _typeLookupFromXmlHashtable[hashString] = typeAndSerializer;
                }
            }
 
            // If we've found a TypeAndSerializer, check whether we have reflected for the
            // serializer information yet.  If not, then do it now.
            if (typeAndSerializer != null && !typeAndSerializer.IsSerializerTypeSet)
            {
                // Check for SerializerAttribute on the type. The serializer for the type is evaluated
                // the very first time we create a new data strcuture for the given type.
                typeAndSerializer.SerializerType = GetXamlSerializerForType(typeAndSerializer.ObjectType);
                typeAndSerializer.IsSerializerTypeSet = true;
            }
 
            return typeAndSerializer;
        }
 
#if PBTCOMPILER
        private static bool IsFriendAssembly(Assembly assembly)
        {
            // WinFX assemblies can never be friends of compiled assemblies, so just bail out.
            if (assembly == XamlTypeMapper.AssemblyPF ||
                assembly == XamlTypeMapper.AssemblyPC ||
                assembly == XamlTypeMapper.AssemblyWB)
            {
                return false;
            }
 
            return ReflectionHelper.IsFriendAssembly(assembly);
        }
 
        private static bool IsInternalAllowedOnType(Type type)
        {
            bool isInternalAllowed = ReflectionHelper.LocalAssemblyName == type.Assembly.GetName().Name ||
                                     IsFriendAssembly(type.Assembly);
            _hasInternals = _hasInternals || isInternalAllowed;
            return isInternalAllowed;
        }
 
        private static bool IsInternalAllowedOnType(NamespaceMapEntry namespaceMap)
        {
            bool isInternalAllowed = namespaceMap.LocalAssembly || IsFriendAssembly(namespaceMap.Assembly);
            _hasInternals = _hasInternals || isInternalAllowed;
            return isInternalAllowed;
        }
 
        internal static bool HasInternals
        {
            get { return _hasInternals; }
            set { _hasInternals = value; }
        }
 
        internal static bool HasLocalReference
        {
            get
            {
                return _hasLocalReference;
            }
        }
#endif
 
        /// <summary>
        /// Create a TypeAndSerializer object for the passed data, if a valid Type
        /// is found.
        /// </summary>
        private TypeAndSerializer CreateTypeAndSerializer(
                string    xmlNamespace,     // xml namespace for the type
                string    localName)        // local name of the type without any '.'
        {
            TypeAndSerializer typeAndSerializer = null;
            NamespaceMapEntry[] namespaceMaps = GetNamespaceMapEntries(xmlNamespace);
 
            if (namespaceMaps != null)
            {
                // We'll do a first pass with only known types
                // and then do a second pass with full reflection
                bool knownTypesOnly = true;
                for (int count = 0; count < namespaceMaps.Length;)
                {
                    NamespaceMapEntry namespaceMap = namespaceMaps[count];
                    if (null != namespaceMap)
                    {
                        Type objectType = GetObjectType(namespaceMap, localName, knownTypesOnly);
                        if (null != objectType)
                        {
                            // A non-public type is never allowable, except for internal types
                            // in local or friend assemblies, so catch it here.
                            if (!ReflectionHelper.IsPublicType(objectType))
                            {
#if PBTCOMPILER
                                // Don't allow internal known types in case we have any.
                                if (knownTypesOnly ||
                                    !ReflectionHelper.IsInternalType(objectType) ||
                                    !IsInternalAllowedOnType(namespaceMap))
#else
                                // Give Full Trust callers a chance to resolve legitimate internal types.
                                // This can be used by tools like designers and localizers running in FT.
                                if (!IsInternalTypeAllowedInFullTrust(objectType))
#endif
                                {
                                    ThrowException(nameof(SR.ParserPublicType), objectType.Name);
                                }
                            }
                            // Create new data structure to store information for the current type
                            typeAndSerializer = new TypeAndSerializer();
                            typeAndSerializer.ObjectType = objectType;
 
                            break;
                        }
                    }
 
                    count++;
                    if (knownTypesOnly && (count == namespaceMaps.Length))
                    {
                        // Reset for second pass
                        knownTypesOnly = false;
                        count = 0;
                    }
                }
            }
            return typeAndSerializer;
        }
 
 
        /// <summary>
        /// Return the Type that corresponds to a localName within a given clr namespace
        /// in a given assembly
        /// </summary>
        /// <param name="namespaceMap">Specifies the CLR namespace and Assembly to look in</param>
        /// <param name="localName">The name of the type</param>
        /// <param name="knownTypesOnly">Search only known types</param>
        /// <returns>Type of object that corresponds to localName</returns>
        private Type GetObjectType(
            NamespaceMapEntry namespaceMap,
            string            localName,
            bool              knownTypesOnly)
        {
            Debug.Assert(namespaceMap.ClrNamespace != null,"Null CLR Namespace");
            Debug.Assert(localName != null,"Null localName");
 
            Type type = null;
 
            // Construct the full type name by concatenating the clr namespace and the local name
 
            if (knownTypesOnly)
            {
                short typeID = BamlMapTable.GetKnownTypeIdFromName(namespaceMap.AssemblyName, namespaceMap.ClrNamespace, localName);
                if (typeID != 0)
                {
                    type = BamlMapTable.GetKnownTypeFromId(typeID);
                }
            }
            else
            {
               Assembly assembly ;
#if PBTCOMPILER
                try
                {
#endif
                    // This may not work if the assembly is not present at compile time, so allow for that.
                    // At runtime it had better be there, so don't ignore it.
                    assembly = namespaceMap.Assembly;
#if PBTCOMPILER
                }
                catch (FileNotFoundException)
                {
                    assembly = null;
                }
#endif
 
                if (null != assembly)
                {
                    // Type loads may fail if all the prerequisite assemblies haven't been loaded
                    // yet.  In this case, try one more time after loaded all assemblies that the
                    // compiler may have told the XamlTypeMapper about.
                    string fullTypeName = $"{namespaceMap.ClrNamespace}.{localName}";
                    try
                    {
                        type = assembly.GetType(fullTypeName);
                    }
                    catch (Exception e)
                    {
                        if (CriticalExceptions.IsCriticalException(e))
                        {
                           throw;
                        }
                        else
                        {
                            if (LoadReferenceAssemblies())
                            {
                                try
                                {
                                    type = assembly.GetType(fullTypeName);
                                }
                                catch (ArgumentException)
                                {
                                    // A null type is allowable, and the caller will catch it
                                    type = null;
                                }
                            }
                        }
                    }
                }
            }
 
            return type;
        }
 
        internal int GetCustomBamlSerializerIdForType(Type objectType)
        {
            // support for xaml -> custom binary and custom binary -> object.
            if (objectType == KnownTypes.Types[(int)KnownElements.Brush])
            {
                return (int)KnownElements.XamlBrushSerializer;
            }
            else if (objectType == KnownTypes.Types[(int)KnownElements.Geometry] ||
                     objectType == KnownTypes.Types[(int)KnownElements.StreamGeometry])
            {
                //
                // The only type of geometry that can be serialized to a string is
                // a StreamGeometry, so if objectType is Geometry and we're getting here
                // then the attribute must in fact be a StreamGeometry.
                //
                return (int)KnownElements.XamlPathDataSerializer;
            }
            else if (objectType == KnownTypes.Types[(int)KnownElements.Point3DCollection])
            {
                return (int)KnownElements.XamlPoint3DCollectionSerializer;
            }
            else if (objectType == KnownTypes.Types[(int)KnownElements.Vector3DCollection])
            {
                return (int)KnownElements.XamlVector3DCollectionSerializer;
            }
            else if (objectType == KnownTypes.Types[(int)KnownElements.PointCollection])
            {
                return (int)KnownElements.XamlPointCollectionSerializer;
            }
            else if (objectType == KnownTypes.Types[(int)KnownElements.Int32Collection])
            {
                return (int)KnownElements.XamlInt32CollectionSerializer;
            }
 
            return 0;
        }
 
        /// <summary>
        /// Sees if type has a Xaml serializer attribute that gives the
        /// type name of the serializer and figure out the type.
        /// </summary>
        internal Type GetXamlSerializerForType(Type objectType)
        {
            // support for xaml -> baml and baml -> objects
            if (objectType == KnownTypes.Types[(int)KnownElements.Style])
            {
                return typeof(XamlStyleSerializer);
            }
            else if (KnownTypes.Types[(int)KnownElements.FrameworkTemplate].IsAssignableFrom(objectType))
            {
                return typeof(XamlTemplateSerializer);
            }
 
            return null;
        }
 
#if !PBTCOMPILER
        internal static Type GetInternalTypeHelperTypeFromAssembly(ParserContext pc)
        {
            Assembly a = pc.StreamCreatedAssembly;
            if (a == null)
            {
                return null;
            }
 
            Type ithType = a.GetType($"{GeneratedNamespace}.{GeneratedInternalTypeHelperClassName}");
            if (ithType == null)
            {
                // if GITH is not found, try to see if a root namespace was implicitly added to it.
                // This would be the case for assemblies built with VB that had a RootNamespace
                // property specified in the project file.
                RootNamespaceAttribute rnsa = (RootNamespaceAttribute)Attribute.GetCustomAttribute(a, typeof(RootNamespaceAttribute));
                if (rnsa != null)
                {
                    string rootNamespace = rnsa.Namespace;
                    ithType = a.GetType($"{rootNamespace}.{GeneratedNamespace}.{GeneratedInternalTypeHelperClassName}");
                }
            }
 
            return ithType;
        }
 
        private static InternalTypeHelper GetInternalTypeHelperFromAssembly(ParserContext pc)
        {
            InternalTypeHelper ith = null;
            Type ithType = GetInternalTypeHelperTypeFromAssembly(pc);
            if (ithType != null)
            {
                ith = (InternalTypeHelper)Activator.CreateInstance(ithType);
            }
            return ith;
        }
 
        internal static object CreateInternalInstance(ParserContext pc, Type type)
        {
            object instance = Activator.CreateInstance(type,
                                                BindingFlags.Public |
                                                BindingFlags.NonPublic |
                                                BindingFlags.Instance |
                                                BindingFlags.CreateInstance,
                                                null,
                                                null,
                                                TypeConverterHelper.InvariantEnglishUS);
 
            return instance;
        }
 
        internal static object GetInternalPropertyValue(ParserContext pc, object rootElement, PropertyInfo pi, object target)
        {
            object propValue = null;
            bool isPublicProperty = false;
            bool allowProtected = (rootElement is IComponentConnector) && (rootElement == target);
            bool isAllowedProperty = IsAllowedPropertyGet(pi, allowProtected, out isPublicProperty);
 
            if (isAllowedProperty)
            {
                propValue = pi.GetValue(target, BindingFlags.Default, null, null, TypeConverterHelper.InvariantEnglishUS);
            }
 
            return propValue;
        }
 
        internal static bool SetInternalPropertyValue(ParserContext pc, object rootElement, PropertyInfo pi, object target, object value)
        {
            bool isPublicProperty = false;
            bool allowProtected = (rootElement is IComponentConnector) && (rootElement == target);
            bool isAllowedProperty = IsAllowedPropertySet(pi, allowProtected, out isPublicProperty);
 
            if (isAllowedProperty)
            {
                pi.SetValue(target, value, BindingFlags.Default, null, null, TypeConverterHelper.InvariantEnglishUS);
                return true;
            }
 
            return false;
        }
 
        internal static Delegate CreateDelegate(ParserContext pc, Type delegateType, object target, string handler)
        {
            Delegate d = null;
            bool isAllowedDelegateType = ReflectionHelper.IsPublicType(delegateType) || ReflectionHelper.IsInternalType(delegateType);
 
            if (isAllowedDelegateType)
            {
                 d = Delegate.CreateDelegate(delegateType, target, handler);
            }
 
            return d;
        }
 
        internal static bool AddInternalEventHandler(ParserContext pc, object rootElement, EventInfo eventInfo, object target, Delegate handler)
        {
            bool isPublicEvent = false;
            bool allowProtected = rootElement == target;
            bool isAllowedEvent = IsAllowedEvent(eventInfo, allowProtected, out isPublicEvent);
 
            if (isAllowedEvent)
            {
                eventInfo.AddEventHandler(target, handler);
                return true;
            }
 
            return false;
        }
#endif
 
        // Return true if this is a locally compiled assembly
        internal bool IsLocalAssembly(string namespaceUri)
        {
            bool localAssembly = false;
#if PBTCOMPILER
            NamespaceMapEntry[] namespaceMaps = GetNamespaceMapEntries(namespaceUri);
            localAssembly = (namespaceMaps != null && namespaceMaps.Length == 1 && namespaceMaps[0].LocalAssembly);
#endif
            return localAssembly;
        }
 
        /// <summary>
        /// Given a string of the format MyNs:MyButton return the type that it refers to.  This uses
        /// the XmlnsDictionary in the passed parse context to resolve prefixes on the
        /// type names
        /// </summary>
        internal Type GetTypeFromBaseString(
            string        typeString,
            ParserContext context,
            bool          throwOnError)
        {
            string xmlns = string.Empty;
            Type keyObject = null;
            // Check if the typeString is of the form xmlns:type.  If so, get
            // the appropriate mapped NamespaceURI.  If not, use the default URI
            int colonIndex = typeString.IndexOf(':');
            if (colonIndex == -1)
            {
                xmlns = context.XmlnsDictionary[string.Empty];
                if (xmlns == null)
                {
                    ThrowException(nameof(SR.ParserUndeclaredNS), string.Empty);
                }
            }
            else
            {
                string prefix = typeString.Substring(0, colonIndex);
                xmlns = context.XmlnsDictionary[prefix];
                if (xmlns == null)
                {
                    ThrowException(nameof(SR.ParserUndeclaredNS), prefix);
                }
                else
                {
                    typeString = typeString.Substring(colonIndex + 1);
                }
            }
 
#if !PBTCOMPILER
            // Optimize for SystemMetric types that are very frequently used.
            if (string.Equals(xmlns, XamlReaderHelper.DefaultNamespaceURI, StringComparison.Ordinal))
            {
                switch (typeString)
                {
                    case "SystemParameters":
                        keyObject = typeof(SystemParameters);
                        break;
 
                    case "SystemColors":
                        keyObject = typeof(SystemColors);
                        break;
 
                    case "SystemFonts":
                        keyObject = typeof(SystemFonts);
                        break;
                }
            }
#endif
            if (keyObject == null)
            {
                keyObject = GetType(xmlns, typeString);
            }
 
            if (keyObject == null && throwOnError)
            {
                // if local type, then don't throw as it may be resolved in pass2.
                // it is upto the caller who has context about compilation passes
                // to throw as appropriate in Pass2 if the type is still not found.
                if (!IsLocalAssembly(xmlns))
                {
                    _lineNumber = context != null ? context.LineNumber : 0;
                    _linePosition = context != null ? context.LinePosition : 0;
 
                    ThrowException(nameof(SR.ParserResourceKeyType), typeString);
                }
            }
 
            return keyObject;
        }
 
#if PBTCOMPILER
        internal Type GetTypeArgsType(
            string typeString,
            ParserContext context,
            out string localTypeArgClassName,
            out string localTypeArgNamespace)
        {
            Type t = null;
            localTypeArgClassName = string.Empty;
            localTypeArgNamespace = string.Empty;
 
            // Check if the typeString is of the form xmlns:type.  If so, get
            // the appropriate mapped NamespaceURI.  If not, use the default URI
            int colonIndex = typeString.IndexOf(':');
            if (colonIndex == -1)
            {
                string xmlns = context.XmlnsDictionary[string.Empty];
                if (xmlns == null)
                {
                    ThrowException(nameof(SR.ParserUndeclaredNS), string.Empty);
                }
                else
                {
                    t = GetType(xmlns, typeString);
                }
            }
            else
            {
                string prefix = typeString.Substring(0, colonIndex);
                string xmlns = context.XmlnsDictionary[prefix];
                if (xmlns == null)
                {
                    ThrowException(nameof(SR.ParserUndeclaredNS), prefix);
                }
                else
                {
                    NamespaceMapEntry[] namespaceMaps = GetNamespaceMapEntries(xmlns);
                    typeString = typeString.Substring(colonIndex + 1);
                    bool isLocalArg = namespaceMaps != null &&
                                      namespaceMaps.Length == 1 &&
                                      namespaceMaps[0].LocalAssembly;
 
                    if (isLocalArg)
                    {
                        localTypeArgNamespace = namespaceMaps[0].ClrNamespace;
                        localTypeArgClassName = typeString;
                    }
                    else
                    {
                        t = GetType(xmlns, typeString);
                    }
                }
            }
 
            return t;
        }
#endif
 
        /// <summary>
        /// Helper method given a type returns the Cached information for the type.  If there
        /// is no existing cached information for that type, a new cache object is created
        /// and added to the cache.
        /// </summary>
        private TypeInformationCacheData GetCachedInformationForType(Type type)
        {
            TypeInformationCacheData typeInformationCacheData;
            typeInformationCacheData = _typeInformationCache[type] as TypeInformationCacheData;
            if (null == typeInformationCacheData)
            {
                typeInformationCacheData = new TypeInformationCacheData(type.BaseType);
                typeInformationCacheData.ClrNamespace = type.Namespace;
 
                _typeInformationCache[type] = typeInformationCacheData;
            }
 
            return typeInformationCacheData;
        }
 
#if !PBTCOMPILER
 
        /// <summary>
        /// Returns the type's BaseType. This is cached because the .net Type.BaseType()
        /// call is expensive.
        /// </summary>
        private Type GetCachedBaseType(Type t)
        {
            TypeInformationCacheData typeInformation = GetCachedInformationForType(t);
 
            return typeInformation.BaseType;
        }
 
        /***************************************************************************\
        *
        * XamlTypeMapper.ProcessNameString
        *
        * Given a name in markup, extract and process the prefix if any.
        *
        \***************************************************************************/
 
        internal static string ProcessNameString(ParserContext parserContext, ref string nameString)
        {
            // For certain parts of the styling markup, a property is specified as an
            //  attribute value.  This may include the namespace specification.  Normally
            //  when we encounter this in an attribute the XML parser processes the name-
            //  space for us.  But when it's the value we'll have to deal with it our-
            //  selves.  Look for the namespace specifier and extract it for namespace lookup.
            //  "foons:BarClass.BazProp" -> "http://www.example.com" + "BarClass.BazProp"
 
            // The colon is what we look for to determine if there's a namespace prefix specifier.
            int nsIndex = nameString.IndexOf(':');
            string nsPrefix = string.Empty;
            if( nsIndex != -1 )
            {
                // Found a namespace prefix separator, so create replacement propertyName.
                // String processing - split "foons" from "BarClass.BazProp"
                nsPrefix = nameString.Substring (0, nsIndex);
                nameString = nameString.Substring (nsIndex + 1);
            }
 
            // Find the namespace, even if its the default one
            string namespaceURI = parserContext.XmlnsDictionary[nsPrefix];
            if (namespaceURI == null)
            {
                parserContext.XamlTypeMapper.ThrowException(nameof(SR.ParserPrefixNSProperty), nsPrefix, nameString);
            }
 
            return namespaceURI;
        }
 
        /***************************************************************************\
        *
        * XamlTypeMapper.ParsePropertyName
        *
        * Given a property name, find the associated DependencyProperty and return it.
        *
        \***************************************************************************/
 
        internal static DependencyProperty ParsePropertyName(
                ParserContext   parserContext,
                string          propertyName,
            ref Type            ownerType)
        {
            string namespaceURI = ProcessNameString(parserContext, ref propertyName);
 
            DependencyProperty dp = parserContext.XamlTypeMapper.DependencyPropertyFromName(
                                            propertyName,
                                            namespaceURI,
                                            ref ownerType);
 
            return dp;
        }
 
        /***************************************************************************\
        *
        * XamlTypeMapper.ParseEventName
        *
        * Given an event name, find the associated RoutedEvent and return it.
        *
        \***************************************************************************/
 
        internal static RoutedEvent ParseEventName(
            ParserContext   parserContext,
            string          eventName,
            Type            ownerType)
        {
            string namespaceURI = ProcessNameString(parserContext, ref eventName);
 
            RoutedEvent Event = parserContext.XamlTypeMapper.GetRoutedEvent(
                ownerType, namespaceURI, eventName);
 
            return Event;
        }
 
#endif
 
        /// <summary>
        /// Return an object of the passed type.
        /// </summary>
        /// <remarks>
        /// If the type is a KnownElement (which it likely will be) it is faster
        /// to create it using the KnownTypes hardcoded constructors, so check that
        /// first before using the Activator.CreateInstance fallback.
        /// </remarks>
        internal object CreateInstance(Type t)
        {
            object o = null;
#if !PBTCOMPILER
            short typeId = BamlMapTable.GetKnownTypeIdFromType(t);
            if (typeId < 0)
            {
                o = MapTable.CreateKnownTypeFromId(typeId);
            }
            else
            {
#endif
                o = Activator.CreateInstance(t,
                                             BindingFlags.Instance | BindingFlags.CreateInstance | BindingFlags.Public,
                                             null,
                                             null,
                                             TypeConverterHelper.InvariantEnglishUS);
#if !PBTCOMPILER
            }
#endif
            return o;
        }
 
#endregion Types
 
#region Namespaces
 
        // Return true if the passed namespace is known, meaning that it maps
        // to a set of assemblies and clr namespaces
        internal bool IsXmlNamespaceKnown(
                string xmlNamespace,
            out string newXmlNamespace)
        {
            bool result;
 
            // if the namespace is empty, then there's no need to do all the extra work associated with getting the
            // namespace map entries.  Just return false.
            if (String.IsNullOrEmpty(xmlNamespace))
            {
                result = false;
                newXmlNamespace = null;
            }
            else
            {
                NamespaceMapEntry[] namespaceMaps = GetNamespaceMapEntries(xmlNamespace);
                if (_xmlnsCache == null)
                {
#if PBTCOMPILER
                    Debug.Assert(false, "Should initialize cache prior to compiling");
#else
                    _xmlnsCache = new XmlnsCache();
#endif
                }
                newXmlNamespace = _xmlnsCache.GetNewXmlnamespace(xmlNamespace);
 
                // if the xmlNamespace has valid entries or is mapped to another namespace, then it is known.
                result = (namespaceMaps != null && namespaceMaps.Length > 0) ||
                              !String.IsNullOrEmpty(newXmlNamespace);
            }
 
            return result; // return variable isn't needed, just makes debugging easier.
        }
 
 
#if !PBTCOMPILER
 
        //
        // Pass xmlNamespace to AssemblyList mapping to xmlnsCache so that the xmlnsCache
        // can take the assembly list to get the right xmlns->clrns mapping later.
        //
        internal void SetUriToAssemblyNameMapping(string xmlNamespace, short[] assemblyIds)
        {
            //
            // If the xmlNamespace is for a mapping,  there is no need to ask for xmlnsCache
            // to get xmlns->clrns mapping.
            //
            if (xmlNamespace.StartsWith(XamlReaderHelper.MappingProtocol, StringComparison.Ordinal))
            {
                return;
            }
 
            if (_xmlnsCache == null)
            {
                _xmlnsCache = new XmlnsCache();
            }
 
            string[] asmNameList = null;
 
            if (assemblyIds != null && assemblyIds.Length > 0)
            {
                asmNameList = new string[assemblyIds.Length];
 
                for (int i = 0; i < assemblyIds.Length; i++)
                {
                    BamlAssemblyInfoRecord assemblyInfo = MapTable.GetAssemblyInfoFromId(assemblyIds[i]);
                    asmNameList[i] = assemblyInfo.AssemblyFullName;
                }
            }
 
            _xmlnsCache.SetUriToAssemblyNameMapping(xmlNamespace, asmNameList);
        }
 
 
#endif
 
        ///<summary>
        /// Returns a NamespaceMapEntry array given a xmlNamespace.  Each
        /// NamespaceMapEntry contains information the XamlTypeMapper uses for Mapping between an xml
        /// XmlNamespace and what Assembly, Namespace to look in.
        ///</summary>
        ///<param name="xmlNamespace">
        /// The xmlNamespace for the Map
        ///</param>
        ///<returns>
        /// Returns an Array of NamespaceMapEntry
        ///</returns>
        internal NamespaceMapEntry[] GetNamespaceMapEntries(string xmlNamespace)
        {
            NamespaceMapEntry[] namespaceMaps = null;
 
            // check out hash and if already have resolved the Uri
            // don't resolve again.
            namespaceMaps = _namespaceMapHashList[xmlNamespace] as NamespaceMapEntry[];
 
            if (null == namespaceMaps)
            {
                ArrayList namespaceMapArray = new ArrayList(6);
 
                // this is the first time the XmlNamespace has been requested
                // add items from the namespaceMap and then walk the assembly
                // list to find matching items.
 
                if (null != _namespaceMaps)
                {
                    // need to find out the total number of entries by asking each hash
                    // review, may be better to sort these firt time through
                    // assumption here that the namespaceMap entries are small.
                    for (int i = 0; i < _namespaceMaps.Length; i++)
                    {
                        NamespaceMapEntry namespaceMap = _namespaceMaps[i];
 
                        if (namespaceMap.XmlNamespace == xmlNamespace)
                        {
                            namespaceMapArray.Add(namespaceMap);
                        }
                    }
                }
 
 
                List<ClrNamespaceAssemblyPair> namespaceAssemblyPair;
                // Check for Processing instructions for mapping.  If that fails,
                // check for Xmlns definition files.
                if (PITable.Contains(xmlNamespace))
                {
                    namespaceAssemblyPair = new List<ClrNamespaceAssemblyPair>(1);
                    namespaceAssemblyPair.Add((ClrNamespaceAssemblyPair)PITable[xmlNamespace]);
                }
                else
                {
                    namespaceAssemblyPair = GetClrNamespacePairFromCache(xmlNamespace);
                }
 
                // now walk through any using statements we got and add them
                if (null != namespaceAssemblyPair)
                {
                    for (int j = 0; j < namespaceAssemblyPair.Count; j++)
                    {
                        ClrNamespaceAssemblyPair mapping = namespaceAssemblyPair[j];
                        string          usingAssemblyName = null;
                        string          path =  AssemblyPathFor(mapping.AssemblyName);
 
                        // using could either have an assembly or not, if it does
                        // have an assembly just need to add this one entry, if
                        // no assembly map in the referenced assemblies.
 
                        if (
#if PBTCOMPILER
                            mapping.LocalAssembly ||
#endif
                            (!(String.IsNullOrEmpty(mapping.AssemblyName)) && !(String.IsNullOrEmpty(mapping.ClrNamespace))) )
                        {
                            usingAssemblyName = mapping.AssemblyName;
                            NamespaceMapEntry nsMap = new NamespaceMapEntry(xmlNamespace,
                                usingAssemblyName,mapping.ClrNamespace,path);
 
#if PBTCOMPILER
                            nsMap.LocalAssembly = mapping.LocalAssembly;
                            // if xaml has local components, then it could have internals
                            // but there is no way to determine this until pass2. But we
                            // need to set this here in order to generate the InternalTypeHelper
                            // in pass1.
                            if (nsMap.LocalAssembly)
                            {
                                _hasLocalReference = true;
                            }
#endif
 
                            namespaceMapArray.Add(nsMap);
                        }
 
                        if (!String.IsNullOrEmpty(mapping.ClrNamespace))
                        {
                            // Also add in any assembly from the AssemblyNames collection
                            for (int k = 0; k < _assemblyNames.Length; k++)
                            {
                                if (usingAssemblyName == null)
                                {
                                    namespaceMapArray.Add(new NamespaceMapEntry(xmlNamespace,
                                                      _assemblyNames[k],
                                                      mapping.ClrNamespace,
                                                      path));
                                }
                                else
                                {
                                    // If we have a using Assembly, then only add assemblies from
                                    // AssemblyNames that match the using Assembly.
                                    int charIndex = _assemblyNames[k].LastIndexOf('\\');
                                    if (charIndex > 0 &&
                                        _assemblyNames[k].Substring(charIndex + 1) == usingAssemblyName)
                                    {
                                        namespaceMapArray.Add(new NamespaceMapEntry(xmlNamespace,
                                                        _assemblyNames[k],
                                                        mapping.ClrNamespace,
                                                        path));
                                    }
                                }
                            }
                        }
                    }
                }
 
                // convert to a namespaceMap
                namespaceMaps = (NamespaceMapEntry[]) namespaceMapArray.ToArray(typeof(NamespaceMapEntry));
 
                // add to hash even if not items so we don't do this work again.
                if (null != namespaceMaps)
                {
                    _namespaceMapHashList.Add(xmlNamespace,namespaceMaps);
                }
            }
 
            return namespaceMaps;
        }
 
 
#if PBTCOMPILER

        /// <summary>
        /// Invalide the namespace mapping cache associated with a namespace. This should be done
        /// when the PITable has been changed and the mapping cache might have been built for the
        /// namespace already.
        /// </summary>
        /// <param name="xmlNamespace">The namespace to for whose cache to invalidate</param>
        internal void InvalidateMappingCache(string xmlNamespace)
        {
            _namespaceMapHashList.Remove(xmlNamespace);
        }
 
        /// <summary>
        /// Set up the XmlnsCache use for resolving namespaces to use only the assembly path
        /// table that has been built up by the XamlTypeMapper.
        /// </summary>
        internal void InitializeReferenceXmlnsCache()
        {
            _xmlnsCache = new XmlnsCache(_assemblyPathTable);
        }
 
#else
        // Get the xml namespace from the _piReverseTable that corresponds to the
        // passed type full name and assembly name
        internal string GetXmlNamespace(
            string  clrNamespaceFullName,
            string  assemblyFullName)
        {
            string upperAssemblyName = assemblyFullName.ToUpper(
                                              TypeConverterHelper.InvariantEnglishUS);
 
            String fullName = $"{clrNamespaceFullName}#{upperAssemblyName}";
 
            String ret;
 
            if (_piReverseTable.TryGetValue(fullName, out ret) && ret != null)
            {
                return ret;
            }
            else
            {
               return string.Empty;
            }
        }
 
        /// <summary>
        /// Given a Type returns it's .net Namespace. This is cached because each call
        /// to .urtNamspace allocates a string.
        /// </summary>
        private string GetCachedNamespace(Type t)
        {
            TypeInformationCacheData typeInformation = GetCachedInformationForType(t);
 
            return typeInformation.ClrNamespace;
        }
#endif
 
        /// <summary>
        /// Check an Xml namespace URI and loads the associated Clr namespaces and assemblies
        /// into ClrNamespaceAssemblyPair structures.
        ///  Throws an exception if no valid namespaces are found.
        /// </summary>
        /// <param name="namespaceUri">Xml namespace that maps to one or more Clr namespace
        /// and assembly pairs</param>
        /// <returns>array of ClrNamespaceAssemblyPair structures</returns>
        internal static List<ClrNamespaceAssemblyPair> GetClrNamespacePairFromCache(
                string namespaceUri)
        {
            List<ClrNamespaceAssemblyPair> mappingArray = null;
 
            if (_xmlnsCache == null)
            {
#if PBTCOMPILER
                Debug.Assert(false, "Should initialize cache prior to compiling");
#else
                _xmlnsCache = new XmlnsCache();
#endif
            }
 
            mappingArray = _xmlnsCache.GetMappingArray(namespaceUri);
 
            return mappingArray;
        }
 
#endregion Namespaces
 
#region TypeConverters
 
        // Returns the Type of the TypeConverter for the given type.
        // Returns null if not found.
        internal Type GetTypeConverterType(Type type)
        {
            Debug.Assert(null != type, "Null passed for type to GetTypeConverterType");
            TypeInformationCacheData typeData = GetCachedInformationForType(type) as TypeInformationCacheData;
            Type converterType = null;
 
            if (null != typeData.TypeConverterType)
            {
                converterType = typeData.TypeConverterType;
                return converterType;
            }
 
            // Check for known TypeConverters first. These are always public.
            converterType = MapTable.GetKnownConverterTypeFromType(type);
            if (converterType == null)
            {
                // If not found, next try looking for the TypeConverter for the type using reflection.
                converterType = TypeConverterHelper.GetConverterType(type);
                if (converterType == null)
                {
                    converterType = TypeConverterHelper.GetCoreConverterTypeFromCustomType(type);
                }
            }
 
            typeData.TypeConverterType = converterType;
            return converterType;
        }
 
#if !PBTCOMPILER
        // Returns the TypeConverter for the given type
        // Throws a XamlParseException if no TypeConverter is found.
        internal TypeConverter GetTypeConverter(Type type)
        {
            Debug.Assert(null != type, "Null passed for type to GetTypeConverter");
 
            TypeInformationCacheData typeData = GetCachedInformationForType(type) as TypeInformationCacheData;
            TypeConverter typeConverter = null;
 
            // if the TypeConverter for this type was ever successfully
            // queried before it should have a non-null value.
            if (null != typeData.Converter)
            {
                typeConverter = typeData.Converter;
                return typeConverter;
            }
 
            // Check for known TypeConverters first. These are always public.
            typeConverter = MapTable.GetKnownConverterFromType(type);
            if (typeConverter == null)
            {
                // If not found, next try looking for the TypeConverter for the type using reflection.
                Type converterType = TypeConverterHelper.GetConverterType(type);
                if (converterType == null)
                {
                    typeConverter = TypeConverterHelper.GetCoreConverterFromCustomType(type);
                }
                else
                {
                    typeConverter = CreateInstance(converterType) as TypeConverter;
                }
            }
 
            typeData.Converter = typeConverter;
 
            if (null == typeConverter)
            {
                ThrowException(nameof(SR.ParserNoTypeConv), type.Name);
            }
 
            return typeConverter;
        }
#endif
 
        // Returns the Type of the TypeConverter applied to the given property itself.
        // Returns null if not found.
        internal Type GetPropertyConverterType(Type propType, object dpOrPiOrMi)
        {
            Debug.Assert(null != propType, "Null passed for propType to GetPropertyConverterType");
            Type converterType = null;
 
            // If the current value being parsed is a property value then we must look
            // if there is special TypeConverter specified as attribute for this property
            if (null != dpOrPiOrMi)
            {
#if PBTCOMPILER
                TypeInformationCacheData typeData = GetCachedInformationForType(propType) as TypeInformationCacheData;
                object ret = typeData.PropertyConverters[dpOrPiOrMi];
                if (null != ret)
                {
                    converterType = (Type)ret;
                    return converterType;
                }
                else
#endif
                {
                    // Get the memberInfo from the DP, PropertyInfo(CLR) or MethodInfo(Attached) for the property
                    MemberInfo memberInfo = TypeConverterHelper.GetMemberInfoForPropertyConverter(dpOrPiOrMi);
                    if (memberInfo != null)
                    {
                        // If not found, next try looking for the TypeConverter on the property itself using reflection.
                        converterType = TypeConverterHelper.GetConverterType(memberInfo);
                    }
                }
 
#if PBTCOMPILER
                // Cache the per property TypeConverter type. This doesn't need to be cached at run-time
                // since GetPropertyConverter will be used for getting the actual TypeConveretr instance.
                // This saves us the cost of a HashTable.
                typeData.SetPropertyConverter(dpOrPiOrMi, converterType);
#endif
            }
 
            return converterType;
        }
 
#if !PBTCOMPILER
        // Returns the TypeConverter applied to the given property iself.
        // If not found returns the TypeConverter applied to the given property's type.
        // Throws a XamlParseException if no TypeConverter is found.
        internal TypeConverter GetPropertyConverter(Type propType, object dpOrPiOrMi)
        {
            Debug.Assert(null != propType, "Null passed for propType to GetPropertyConverter");
            TypeConverter typeConverter = null;
 
            TypeInformationCacheData typeData = GetCachedInformationForType(propType) as TypeInformationCacheData;
 
            // If the current value being parsed is a property value then we must look
            // if there is special TypeConverter specified as attribute for this property
            if (null != dpOrPiOrMi)
            {
                object ret = typeData.PropertyConverters[dpOrPiOrMi];
                if (null != ret)
                {
                    typeConverter = (TypeConverter)ret;
                    return typeConverter;
                }
 
                // Get the memberInfo from the DP, PropertyInfo(CLR) or MethodInfo(Attached) for the property
                MemberInfo memberInfo = TypeConverterHelper.GetMemberInfoForPropertyConverter(dpOrPiOrMi);
                if (memberInfo != null)
                {
                    // If not found, next try looking for the TypeConverter on the property itself using reflection.
                    Type converterType = TypeConverterHelper.GetConverterType(memberInfo);
                    if (converterType != null)
                    {
                        // create an instance of the TypeConverter if found
                        typeConverter = CreateInstance(converterType) as TypeConverter;
                    }
                }
            }
 
            // If no TypeConverter is found on the property itself, try to find it based on the property's type
            if (typeConverter == null)
            {
                typeConverter = GetTypeConverter(propType);
            }
 
            // Cache the per property TypeConverter
            if (dpOrPiOrMi != null)
                typeData.SetPropertyConverter(dpOrPiOrMi, typeConverter);
 
            return typeConverter;
        }
#endif
 
#endregion TypeConverters
 
#region Resources
 
        /// <summary>
        /// Given a string, return a key to be used in a dictionary relating to this string.
        /// If the string is a simple string, just return that.  If the string represents a
        /// Typeof declaration, then return the Type that maps to that string.
        /// Note that this can return null if the key is not resolved.  It is up to the caller
        /// to throw the appropriate error message in that case.
        /// </summary>
        internal object GetDictionaryKey(string keyString, ParserContext context)
        {
             if (keyString.Length > 0 &&
                 (Char.IsWhiteSpace(keyString[0]) ||
                  Char.IsWhiteSpace(keyString[keyString.Length-1])))
             {
                keyString = keyString.Trim();
             }
             return keyString;
        }
 
#endregion Resources
 
#if !PBTCOMPILER
 
#region ConstructorInfos
 
        /// <summary>
        /// Fetches the cached ConstructorInfos if there exists one or
        /// then creates a new one and caches it for later.
        /// </summary>
        internal ConstructorData GetConstructors(Type type)
        {
            // Create a cache if it does not already exist
            if (_constructorInformationCache == null)
            {
                _constructorInformationCache = new HybridDictionary(3);
            }
 
            // Add an entry for the current type if it does not already exist
            if (!_constructorInformationCache.Contains(type))
            {
                _constructorInformationCache[type] = new ConstructorData(type.GetConstructors(BindingFlags.Public | BindingFlags.Instance));
            }
 
            // Return the cached value
            return (ConstructorData)_constructorInformationCache[type];
        }
 
        /// <summary>
        /// Helper class that is used to store constructor information for a type
        /// </summary>
        internal class ConstructorData
        {
            #region Constructors
 
            internal ConstructorData(ConstructorInfo[] constructors)
            {
                _constructors = constructors;
            }
 
            #endregion Constructors
 
            #region Methods
 
            /// <summary>
            /// Fetches the cached ParameterInfos if there exists one or
            /// then creates a new one and caches it for later.
            /// </summary>
            internal ParameterInfo[] GetParameters(int constructorIndex)
            {
                // Create a parameters Cache if it does not already exist
                if (_parameters == null)
                {
                    Debug.Assert(_constructors != null, "This operation is legal only after the constructors have been fetched");
                    _parameters = new ParameterInfo[_constructors.Length][];
                }
 
                // Add an entry for the current constructor if it does not already exist
                if (_parameters[constructorIndex] == null)
                {
                    _parameters[constructorIndex] = _constructors[constructorIndex].GetParameters();
                }
 
                // Return the cached value
                return _parameters[constructorIndex];
            }
 
            #endregion Methods
 
            #region Properties
 
            internal ConstructorInfo[] Constructors
            {
                get { return _constructors; }
            }
 
            #endregion Properties
 
            #region Data
 
            private ConstructorInfo[] _constructors;
            private ParameterInfo[][] _parameters;
 
            #endregion Data
        }
 
#endregion ConstructorInfos
 
#endif
 
#region TrimSurroundingWhitespace
 
        /// <summary>
        /// Returns the Cached TrimSurroundingWhitespace for the associated type
        /// We cache this because the reflection lookup on the attribute
        /// is slow.
        /// </summary>
        /// <param name="t">type to return the TrimSurroundingWhitespaceAttribute for</param>
        /// <returns>The TrimSurroundingWhitespace value for t</returns>
        internal bool GetCachedTrimSurroundingWhitespace(Type t)
        {
            TypeInformationCacheData typeInformation = GetCachedInformationForType(t);
 
            // if first time asked for the layout Type get it.
            if (!typeInformation.TrimSurroundingWhitespaceSet)
            {
                typeInformation.TrimSurroundingWhitespace = GetTrimSurroundingWhitespace(t);
                typeInformation.TrimSurroundingWhitespaceSet = true;
            }
 
            return typeInformation.TrimSurroundingWhitespace;
        }
 
        /// <summary>
        ///  Helper function for  use to find out the TrimSurroundingWhitespace
        ///  associated with a Type.
        /// </summary>
        private bool GetTrimSurroundingWhitespace(Type type)
        {
            Debug.Assert(null != type, "null value for type passed to GetWhitespace");
 
            // in retail return default.
            if (null != type)
            {
#if !PBTCOMPILER
                TrimSurroundingWhitespaceAttribute[] trimAttribute =
                    type.GetCustomAttributes(typeof(TrimSurroundingWhitespaceAttribute),true )
                    as TrimSurroundingWhitespaceAttribute[];
 
                if (trimAttribute.Length > 0)
                {
                    Debug.Assert(1 == trimAttribute.Length,"More than one TrimWhitespace Attribute");
                    return true;
                }
#else
                // Reflecting for attributes doesn't work on asmmeta files, so
                // we have to hard code known layout types here.  This is very
                // fragile, but we'll fix it in M8.2. - It's end of M11 already though...
                if (KnownTypes.Types[(int)KnownElements.LineBreak].IsAssignableFrom(type))
                {
                    return true;
                }
#endif
            }
            return false;
        }
 
#endregion TrimSurroundingWhitespace
 
#region Exceptions
 
        //
        // ThrowException wrappers for 0-3 parameter SRIDs
        //
 
        private void ThrowException(string id)
        {
            ThrowExceptionWithLine(SR.GetResourceString(id), null);
        }
 
        internal void ThrowException(string id, string parameter)
        {
            ThrowExceptionWithLine(SR.Format(SR.GetResourceString(id), parameter), null);
        }
 
        private void ThrowException(string id, string parameter1, string parameter2)
        {
            ThrowExceptionWithLine(SR.Format(SR.GetResourceString(id), parameter1, parameter2), null);
        }
 
        private void ThrowException(string id, string parameter1, string parameter2, string parameter3)
        {
            ThrowExceptionWithLine(SR.Format(SR.GetResourceString(id), parameter1, parameter2, parameter3), null);
        }
 
 
 
        //
        // ThrowException wrapper that just adds the line number & position.
        //
 
        internal void ThrowExceptionWithLine(string message, Exception innerException)
        {
            XamlParseException.ThrowException(message, innerException, _lineNumber, _linePosition);
        }
 
 
#endregion Exceptions
 
#region Properties
 
        /// <summary>
        /// Hashtable where key is the xmlNamespace, and value is the
        /// ClrNamespaceAssemblyPair structure containing clrNamespace and assembly
        /// </summary>
        internal HybridDictionary PITable
        {
            get { return _piTable; }
        }
 
 
        /// <summary>
        /// This is the associated BamlMapTable that contains information about what is
        /// in a baml stream.  The XamlTypeMapper uses the map table (if present) as a cache
        /// to store some assembly, type and property information.  If it is not present
        /// then this information is not cached and must be retrieved for every request.
        /// </summary>
        internal BamlMapTable MapTable
        {
            get { return _mapTable; }
            set { _mapTable = value; }
        }
 
        /// <summary>
        /// Line number used for error reporting
        /// </summary>
        internal int LineNumber
        {
            set { _lineNumber = value; }
        }
 
        /// <summary>
        /// Line position used for error reporting
        /// </summary>
        internal int LinePosition
        {
            set { _linePosition = value; }
        }
 
#if !PBTCOMPILER
        /// <summary>
        ///  Return the hashtable that is keyed by xml namespace uri and
        ///  has values that are collection of NamespaceMapEntry objects for that
        ///  xml namespace.
        /// </summary>
        internal Hashtable NamespaceMapHashList
        {
            get { return _namespaceMapHashList; }
        }
 
        internal System.Xaml.XamlSchemaContext SchemaContext
        {
            get
            {
                if (_schemaContext == null)
                {
                    _schemaContext = new XamlTypeMapperSchemaContext(this);
                }
                return _schemaContext;
            }
        }
#else
        // true if the Type Mapper can allow protected attributes.
        // This will be the case for a markup sub-classed root element only.
        internal bool IsProtectedAttributeAllowed
        {
            get { return _isProtectedAttributeAllowed; }
            set { _isProtectedAttributeAllowed = value; }
        }
 
        internal void ResetMapper()
        {
            _piTable.Clear();
            _piReverseTable.Clear();
            _lineNumber = 0;
            _linePosition = 0;
            _isProtectedAttributeAllowed = false;
 
            NamespaceMapEntry[] defaultNsMaps = _namespaceMapHashList[XamlReaderHelper.DefaultNamespaceURI] as NamespaceMapEntry[];
            NamespaceMapEntry[] definitionNsMaps = _namespaceMapHashList[XamlReaderHelper.DefinitionNamespaceURI] as NamespaceMapEntry[];
            NamespaceMapEntry[] definitionMetroNsMaps = _namespaceMapHashList[XamlReaderHelper.DefinitionMetroNamespaceURI] as NamespaceMapEntry[];
 
            _namespaceMapHashList.Clear();
            if (null != defaultNsMaps)
            {
                _namespaceMapHashList.Add(XamlReaderHelper.DefaultNamespaceURI, defaultNsMaps);
            }
            if (null != definitionNsMaps)
            {
                _namespaceMapHashList.Add(XamlReaderHelper.DefinitionNamespaceURI, definitionNsMaps);
            }
            if (null != definitionMetroNsMaps)
            {
                _namespaceMapHashList.Add(XamlReaderHelper.DefinitionMetroNamespaceURI, definitionMetroNsMaps);
            }
        }
#endif
#endregion Properties
 
        #region Data
 
        // Class used for Type information data cache.
        internal class TypeInformationCacheData
        {
            /// <summary>
            /// Create a new instance of the type cache.  Note that the type of this cached
            /// data is not stored anywhere in this object.  The type that this object pertains
            /// to is stored as the key in the _typeInformationCache dictionary.
            /// </summary>
            internal TypeInformationCacheData(Type baseType)
            {
                _baseType = baseType;
            }
 
            /// <summary>
            /// Urt Namespace for this type
            /// </summary>
            internal string ClrNamespace
            {
#if !PBTCOMPILER
                get { return _clrNamespace; }
#endif
                set { _clrNamespace = value; }
            }
 
#if !PBTCOMPILER
            /// <summary>
            /// The parent type in the inheritance hierarchy of this type.  This is
            /// stored here since BaseType lookups take some time.
            /// </summary>
            internal Type BaseType
            {
                get { return _baseType; }
            }
 
            /// <summary>
            /// TypeConverter associted with this type, if there is one.  This is stored
            /// here so that GetTypeConverter does not need to be called as often.
            /// </summary>
            internal TypeConverter Converter
            {
                get { return _typeConverter; }
                set { _typeConverter = value; }
            }
#endif
            // The type of the TypeConverter
            internal Type TypeConverterType
            {
                get { return _typeConverterType; }
                set { _typeConverterType = value; }
            }
 
            /// <summary>
            /// TrimSurroundingWhitespace value for this type.
            /// </summary>
            internal bool TrimSurroundingWhitespace
            {
                get { return _trimSurroundingWhitespace; }
                set { _trimSurroundingWhitespace = value; }
            }
 
            /// <summary>
            /// Flag to indicate if we have cached the TrimSurroundingWhitespace
            /// </summary>
            internal bool TrimSurroundingWhitespaceSet
            {
                get { return _trimSurroundingWhitespaceSet; }
                set { _trimSurroundingWhitespaceSet = value; }
            }
 
            /// <summary>
            /// Get the DependencyProperty from the Hashtable of PropertyAndType
            /// keyed by DependencyProperty name
            /// </summary>
            internal PropertyAndType GetPropertyAndType(string dpName)
            {
                if (_dpLookupHashtable == null)
                {
                    _dpLookupHashtable = new Hashtable();
                    return null;
                }
 
                return _dpLookupHashtable[dpName] as PropertyAndType;
            }
 
 
            /// <summary>
            /// Set a new PropertyAndType in the DependencyProperty information Hashtable.
            /// </summary>
            internal void SetPropertyAndType(
                string          dpName,
                PropertyInfo    dpInfo,
                Type            ownerType,
                bool            isInternal)
            {
                Debug.Assert(_dpLookupHashtable != null,
                    "GetPropertyAndType must always be called before SetPropertyAndType");
 
                // add the type taking a lock
                PropertyAndType pAndT = _dpLookupHashtable[dpName] as PropertyAndType;
                if (pAndT == null)
                {
                    _dpLookupHashtable[dpName] = new PropertyAndType(null, dpInfo, false, true, ownerType, isInternal);
                }
                else
                {
                    pAndT.PropInfo = dpInfo;
                    pAndT.PropInfoSet = true;
                    pAndT.IsInternal = isInternal;
                }
            }
 
            /// <summary>
            /// TypeConverters based upon attributes on property
            /// </summary>
            internal HybridDictionary PropertyConverters
            {
                get
                {
                    if (null == _propertyConverters)
                    {
                        _propertyConverters = new HybridDictionary();
                    }
 
                    return _propertyConverters;
                }
            }
 
            /// <summary>
            /// Set a new PropertyConverter for the given property.
            /// NOTE: This method takes a lock on the table. So to set
            /// values into the table you must use this method.
            /// </summary>
            internal void SetPropertyConverter(
                object dpOrPi,
#if !PBTCOMPILER
                TypeConverter converter)
#else
                Type converter)
#endif
            {
                _propertyConverters[dpOrPi] = converter;
            }
 
            // Private data members
            string        _clrNamespace;
            Type          _baseType;
            bool          _trimSurroundingWhitespace;
            Hashtable     _dpLookupHashtable;  // Hashtable of PropertyAndType keyed by dp name
            HybridDictionary     _propertyConverters = new HybridDictionary(); // Dictionary of TypeConverters keyed on dpOrPi
            bool          _trimSurroundingWhitespaceSet;
#if !PBTCOMPILER
            TypeConverter _typeConverter;
#endif
            Type          _typeConverterType;
        }
 
        // DP setter method, PropertyInfo and Type record held in _dpLookupHashtable
        internal class PropertyAndType
        {
            public PropertyAndType (MethodInfo dpSetter,
                                    PropertyInfo dpInfo,
                                    bool setterSet,
                                    bool propInfoSet,
                                    Type ot,
                                    bool isInternal)
            {
                Setter      = dpSetter;
                PropInfo    = dpInfo;
                OwnerType   = ot;
                SetterSet   = setterSet;
                PropInfoSet = propInfoSet;
                IsInternal  = isInternal;
            }
 
            public PropertyInfo PropInfo;
            public MethodInfo   Setter;
            public Type         OwnerType;
            public bool         PropInfoSet;
            public bool         SetterSet;
            public bool         IsInternal;
        }
 
        // Constants that identify special types of string values
        internal const string MarkupExtensionTypeString = "Type ";
        internal const string MarkupExtensionStaticString = "Static ";
//        internal const string MarkupExtensionNullString = "Null";
        internal const string MarkupExtensionDynamicResourceString = "DynamicResource ";
 
        // If the case or name of the assembly name changes in the Framework build,
        // then the following will have to change also.
        internal const string PresentationFrameworkDllName  = "PresentationFramework";
 
        // Namespace & classname of the generated helper class for accessing allowed internal types in PT.
        internal const string GeneratedNamespace = "XamlGeneratedNamespace";
        internal const string GeneratedInternalTypeHelperClassName = "GeneratedInternalTypeHelper";
 
#if !PBTCOMPILER
        internal const string MarkupExtensionTemplateBindingString = "TemplateBinding ";
#else
        private static bool _hasInternals = false;
        private static bool _hasLocalReference = false;
        private bool _isProtectedAttributeAllowed = false;
        internal static Assembly AssemblyWB = null;
        internal static Assembly AssemblyPC = null;
        internal static Assembly AssemblyPF = null;
 
        internal static void Clear()
        {
            _hasInternals = false;
            _hasLocalReference = false;
            AssemblyWB = null;
            AssemblyPC = null;
            AssemblyPF = null;
        }
#endif
        // Map table associated with this XamlTypeMapper.  This contains information
        // about what is stored in BAML.  The XamlTypeMapper makes use of the caches in
        // the BamlMapTable to store some assembly, type and property information.
        BamlMapTable _mapTable;
 
        // Array of assembly names that can be used when resolving clr namespaces
        string[] _assemblyNames;
 
        // array or namespace map entries such as `http:// mappings.
        NamespaceMapEntry[] _namespaceMaps;
 
        // HashTable of cached type lookups and the serializers for that type.  These
        // are always TypeAndSerializer objects
        Hashtable _typeLookupFromXmlHashtable = new Hashtable();
 
        // Hash table of mappings between xmlNamespace and mappings
        Hashtable _namespaceMapHashList = new Hashtable();
 
        // Hashtable where the key is the fullTypeName + '#' + propertyName and the value
        HybridDictionary _typeInformationCache = new HybridDictionary();
 
#if !PBTCOMPILER
        // Hashtable where the key is the type and the value is the set of constructors for that type
        HybridDictionary _constructorInformationCache;
 
        // A SchemaContext that respects the namespace mappings, PIs, and assembly paths
        // passed in to this TypeMapper
        private XamlTypeMapperSchemaContext _schemaContext;
#endif
 
        // Hashtable where key is the xmlNamespace, and value is the
        // ClrNamespaceAssemblyPair structure containing clrNamespace and assembly
        HybridDictionary _piTable =  new HybridDictionary();
 
        // Hashtable where key is the clrNamespace + "#" + assemblyName and the
        // value is the corresponding xmlNamespace.  This is used for fast lookups
        // of xmlnamespace if you know the assembly and clr namespace.
        Dictionary<string, string> _piReverseTable = new Dictionary<string, string>();
 
        // Hashtable where key is the assembly's short name that has been uppercased,
        // and the value is a path where that assembly can be loaded from.
        // Always lock on this object when writing to it
        HybridDictionary _assemblyPathTable = new HybridDictionary();
 
        // true if referenced assemblies in the _assemblyPathTable have been loaded
        bool _referenceAssembliesLoaded = false;
 
        // Line number and position in original Xaml file corresponding to the
        // current BAML record.
        int _lineNumber = 0;
        int _linePosition = 0;
 
        // Cache of namespace and assemblies.
        private static XmlnsCache _xmlnsCache = null;
 
#endregion Data
 
#endregion Internal
    }
 
    // Type of object and type of Serializer for that type.  If this type
    // also contains an [XmlLang] property, this caches the property info also.
    // These are contained in the _typeLookupFromXmlHashtable hastable
    internal class TypeAndSerializer
    {
        public TypeAndSerializer()
        {
        }
 
        public Type ObjectType = null;
        public Type SerializerType = null;
        public bool IsSerializerTypeSet = false;
        public PropertyInfo XmlLangProperty;
    }
 
    /// <summary>
    /// Contains information the XamlTypeMapper uses for Mapping between an xml
    /// XmlNamespace and what Assembly, Namespace to look in.
    /// </summary>
    [DebuggerDisplay("'{_xmlNamespace}'={_clrNamespace}:{_assemblyName}")]
#if PBTCOMPILER
    internal class NamespaceMapEntry
#else
    public class NamespaceMapEntry
#endif
    {
        #region Constructors
 
        ///<summary>
        /// NamespaceMapEntry default constructor
        ///</summary>
        public NamespaceMapEntry()
        {
        }
 
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="xmlNamespace">The XML NamespaceURi</param>
        /// <param name="assemblyName">Assembly to use when resolving a Tag</param>
        /// <param name="clrNamespace">Namespace within the assembly</param>
        public NamespaceMapEntry(string xmlNamespace,string assemblyName,string clrNamespace)
        {
            if (xmlNamespace == null)
                throw new ArgumentNullException("xmlNamespace");
 
            if (assemblyName == null)
                throw new ArgumentNullException("assemblyName");
 
            if (clrNamespace == null)
                throw new ArgumentNullException("clrNamespace");
 
            _xmlNamespace = xmlNamespace;
            _assemblyName = assemblyName;
            _clrNamespace = clrNamespace;
        }
 
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="xmlNamespace">The XML NamespaceURi</param>
        /// <param name="assemblyName">Assembly to use when resolving a Tag</param>
        /// <param name="clrNamespace">Namespace within the assembly</param>
        /// <param name="assemblyPath">Path to use when loading assembly.  This may be null.</param>
         internal NamespaceMapEntry(
                string xmlNamespace,
                string assemblyName,
                string clrNamespace,
                string assemblyPath) : this(xmlNamespace, assemblyName, clrNamespace)
        {
            _assemblyPath = assemblyPath;
        }
 
        #endregion Constructors
 
 
        #region Properties
 
        /// <summary>
        /// Xml namespace specified in the constructor
        /// </summary>
        public string XmlNamespace
        {
            get { return _xmlNamespace; }
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("value");
                }
                if (_xmlNamespace == null)
                {
                    _xmlNamespace = value;
                }
            }
        }
 
        /// <summary>
        /// AssemblyName specified in the constructor
        /// </summary>
        public string AssemblyName
        {
            get { return _assemblyName; }
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("value");
                }
                if (_assemblyName == null)
                {
                    _assemblyName = value;
                }
            }
        }
 
        /// <summary>
        /// ClrNamespace specified within the constructor
        /// </summary>
        public string ClrNamespace
        {
            get { return _clrNamespace; }
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("value");
                }
                if (_clrNamespace == null)
                {
                    _clrNamespace = value;
                }
            }
        }
 
 
        #endregion Properties
 
        /// <summary>
        /// returns instance of the assembly associate with this
        /// namespace map
        /// </summary>
        internal Assembly Assembly
        {
            get
            {
                if (null == _assembly && _assemblyName.Length > 0)
                {
#if PBTCOMPILER
                    // NOTE: At compile time a local assembly can already be loaded if being
                    // referenced by dehydrated assemblies and so we should attempt to return
                    // that.
                    if (_isLocalAssembly)
                    {
                        string assemblyNameLookup = _assemblyName.ToUpper(CultureInfo.InvariantCulture);
 
                        // Check if the assembly has already been loaded.
                        if (!ReflectionHelper.HasAlreadyReflectionOnlyLoaded(assemblyNameLookup))
                        {
                            return null;
                        }
                    }
 
#endif
                    _assembly = ReflectionHelper.LoadAssembly(_assemblyName, _assemblyPath);
                }
 
                return _assembly;
            }
        }
 
        /// <summary>
        /// Get and set the path to use when loading the assembly.
        /// </summary>
        internal string AssemblyPath
        {
            get { return _assemblyPath; }
            set { _assemblyPath = value; }
        }
 
#if PBTCOMPILER
        internal bool LocalAssembly
        {
            get { return _isLocalAssembly; }
            set { _isLocalAssembly = value; }
        }
 
        bool     _isLocalAssembly;
#endif
 
#region Data
 
        string   _xmlNamespace;
        string   _assemblyName;
        string   _assemblyPath;
        Assembly _assembly;
        string   _clrNamespace;
 
#endregion Data
    }
 
    // This is a convenience holder for all the possible IDs that Xaml understands which could
    // be on an object element.
    internal class XamlObjectIds
    {
        public string Name = null;
        public string Uid = null;
        public object Key = null;
    }
 
 
#region XmlParserDefaults Class
 
    // class for getting and setting mapping defaults.
    internal static class XmlParserDefaults
    {
#region Methods
 
        /// <summary>
        ///  Instance of XamlTypeMapper to use if none is specified in the
        ///  ParserContext. XamlTypeMapper returned is has its assembly and namespace
        ///  maps initialized to those set
        ///  via SetDefaultXmlMapping() or one built from our internal defaults.
        /// </summary>
        internal static XamlTypeMapper DefaultMapper
        {
            get
            {
                return new XamlTypeMapper(GetDefaultAssemblyNames(),GetDefaultNamespaceMaps());
            }
        }
 
#endregion Methods
 
#region Properties
 
        /// <summary>
        /// Returns an array of the DefaultAssemblyNames
        /// </summary>
        internal static string[] GetDefaultAssemblyNames()
        {
            return (string[])_defaultAssemblies.Clone();
        }
 
        /// <summary>
        /// Returns array of the DefaultNamespaceMaps
        /// </summary>
        internal static NamespaceMapEntry[] GetDefaultNamespaceMaps()
        {
            return (NamespaceMapEntry[])_defaultNamespaceMapTable.Clone();
        }
 
#endregion Properties
 
#region Data
 
        // array of our defaultAssemblies.
        private static readonly string[] _defaultAssemblies = {"WindowsBase", "PresentationCore", "PresentationFramework"};
 
        // array of namespaceMaps the map an xmlns namespaceURI
        // to the assembly and urtNamespace to search in when resolving the xml
 
        private static readonly NamespaceMapEntry[] _defaultNamespaceMapTable = { };
 
#endregion Data
    }
#endregion XmlParserDefaults Class
}