/// <summary>
        /// Binds a name to type.
        /// </summary>
        /// <param name="typeName">The name of the type to bind.</param>
        /// <param name="debugContext">The debug context to log to.</param>
        /// <returns>
        /// The type that the name has been bound to, or null if the type could not be resolved.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">The typeName argument is null.</exception>
        public override Type BindToType(string typeName, DebugContext debugContext = null)
        {
            if (typeName == null)
            {
                throw new ArgumentNullException("typeName");
            }

            RegisterAllQueuedAssembliesRepeating();

            Type result;

            lock (NAMETOTYPE_LOCK)
            {
                if (typeMap.TryGetValue(typeName, out result) == false)
                {
                    result = this.ParseTypeName(typeName, debugContext);

                    if (result == null && debugContext != null)
                    {
                        debugContext.LogWarning("Failed deserialization type lookup for type name '" + typeName + "'.");
                    }

                    // We allow null values on purpose so we don't have to keep re-performing invalid name lookups
                    typeMap.Add(typeName, result);
                }
            }

            return(result);
        }
        /// <summary>
        /// Bind a type to a name.
        /// </summary>
        /// <param name="type">The type to bind.</param>
        /// <param name="debugContext">The debug context to log to.</param>
        /// <returns>
        /// The name that the type has been bound to.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">The type argument is null.</exception>
        public override string BindToName(Type type, DebugContext debugContext = null)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            string result;

            lock (TYPETONAME_LOCK)
            {
                if (nameMap.TryGetValue(type, out result) == false)
                {
                    if (type.IsGenericType)
                    {
                        // We track down all assemblies in the generic type definition
                        List <Type>        toResolve  = type.GetGenericArguments().ToList();
                        HashSet <Assembly> assemblies = new HashSet <Assembly>();

                        while (toResolve.Count > 0)
                        {
                            var t = toResolve[0];

                            if (t.IsGenericType)
                            {
                                toResolve.AddRange(t.GetGenericArguments());
                            }

                            assemblies.Add(t.Assembly);
                            toResolve.RemoveAt(0);
                        }

                        result = type.FullName + ", " + type.Assembly.GetName().Name;

                        foreach (var ass in assemblies)
                        {
                            result = result.Replace(ass.FullName, ass.GetName().Name);
                        }
                    }
                    else if (type.IsDefined(typeof(CompilerGeneratedAttribute), false))
                    {
                        result = type.FullName + ", " + type.Assembly.GetName().Name;
                    }
                    else
                    {
                        result = type.FullName + ", " + type.Assembly.GetName().Name;
                    }

                    nameMap.Add(type, result);
                }
            }

            return(result);
        }
        private Type ParseGenericAndOrArrayType(string typeName, DebugContext debugContext)
        {
            string        actualTypeName;
            List <string> genericArgNames;

            bool isGeneric;
            bool isArray;
            int  arrayRank;

            if (!TryParseGenericAndOrArrayTypeName(typeName, out actualTypeName, out isGeneric, out genericArgNames, out isArray, out arrayRank))
            {
                return(null);
            }

            Type type = this.BindToType(actualTypeName, debugContext);

            if (type == null)
            {
                return(null);
            }

            if (isGeneric)
            {
                if (!type.IsGenericType)
                {
                    return(null);
                }

                List <Type> args = genericArgTypesList;
                args.Clear();

                for (int i = 0; i < genericArgNames.Count; i++)
                {
                    Type arg = this.BindToType(genericArgNames[i], debugContext);
                    if (arg == null)
                    {
                        return(null);
                    }
                    args.Add(arg);
                }

                var argsArray = args.ToArray();

                if (!type.AreGenericConstraintsSatisfiedBy(argsArray))
                {
                    if (debugContext != null)
                    {
                        string argsStr = "";

                        foreach (var arg in args)
                        {
                            if (argsStr != "")
                            {
                                argsStr += ", ";
                            }
                            argsStr += arg.GetNiceFullName();
                        }

                        debugContext.LogWarning("Deserialization type lookup failure: The generic type arguments '" + argsStr + "' do not satisfy the generic constraints of generic type definition '" + type.GetNiceFullName() + "'. All this parsed from the full type name string: '" + typeName + "'");
                    }

                    return(null);
                }

                type = type.MakeGenericType(argsArray);
            }

            if (isArray)
            {
                type = type.MakeArrayType(arrayRank);
            }

            return(type);
        }
        private Type ParseTypeName(string typeName, DebugContext debugContext)
        {
            Type type;

            lock (ASSEMBLY_LOOKUP_LOCK)
            {
                // Look for custom defined type name lookups defined with the BindTypeNameToTypeAttribute.
                if (customTypeNameToTypeBindings.TryGetValue(typeName, out type))
                {
                    return(type);
                }
            }

            // Let's try it the traditional .NET way
            type = Type.GetType(typeName);
            if (type != null)
            {
                return(type);
            }

            // Generic/array type name handling
            type = ParseGenericAndOrArrayType(typeName, debugContext);
            if (type != null)
            {
                return(type);
            }

            string typeStr, assemblyStr;

            ParseName(typeName, out typeStr, out assemblyStr);

            if (!string.IsNullOrEmpty(typeStr))
            {
                lock (ASSEMBLY_LOOKUP_LOCK)
                {
                    // Look for custom defined type name lookups defined with the BindTypeNameToTypeAttribute.
                    if (customTypeNameToTypeBindings.TryGetValue(typeStr, out type))
                    {
                        return(type);
                    }
                }

                Assembly assembly;

                // Try to load from the named assembly
                if (assemblyStr != null)
                {
                    lock (ASSEMBLY_LOOKUP_LOCK)
                    {
                        assemblyNameLookUp.TryGetValue(assemblyStr, out assembly);
                    }

                    if (assembly == null)
                    {
                        try
                        {
                            assembly = Assembly.Load(assemblyStr);
                        }
                        catch { }
                    }

                    if (assembly != null)
                    {
                        try
                        {
                            type = assembly.GetType(typeStr);
                        }
                        catch { } // Assembly is invalid

                        if (type != null)
                        {
                            return(type);
                        }
                    }
                }

                // Try to check all assemblies for the type string
                var assemblies = AppDomain.CurrentDomain.GetAssemblies();

                for (int i = 0; i < assemblies.Length; i++)
                {
                    assembly = assemblies[i];

                    try
                    {
                        type = assembly.GetType(typeStr, false);
                    }
                    catch { } // Assembly is invalid

                    if (type != null)
                    {
                        return(type);
                    }
                }
            }

            //type = AssemblyUtilities.GetTypeByCachedFullName(typeStr);
            //if (type != null) return type;

            return(null);
        }
 /// <summary>
 /// Binds a name to a type.
 /// </summary>
 /// <param name="typeName">The name of the type to bind.</param>
 /// <param name="debugContext">The debug context to log to.</param>
 /// <returns>The type that the name has been bound to, or null if the type could not be resolved.</returns>
 public abstract Type BindToType(string typeName, DebugContext debugContext = null);
 /// <summary>
 /// Bind a type to a name.
 /// </summary>
 /// <param name="type">The type to bind.</param>
 /// <param name="debugContext">The debug context to log to.</param>
 /// <returns>The name that the type has been bound to.</returns>
 public abstract string BindToName(Type type, DebugContext debugContext = null);