/// <summary>
        /// Parses methods into the dotnet object passed in.
        /// Expects methods to be empty
        /// </summary>
        /// <param name="dotnetObject"></param>
        public void ParseMethods(DotnetObject dotnetObject)
        {
            var dotnetType = dotnetObject.TypeDefinition;

            var methods = dotnetType.Methods;

            // loop through base classes
            while (methods != null)
            {
                ParseMethodsOnType(dotnetObject, methods, dotnetType);

                if (NoInheritedMembers)
                {
                    break;
                }

                var tref = dotnetType.BaseType;
                if (tref == null || tref.FullName == dotnetType.FullName)
                {
                    break;
                }

                dotnetType = tref.Resolve();
                methods    = dotnetType.Methods;
            }
        }
        /// <summary>
        /// Converts a CLR typename to VB or C# type name. Type must passed in as plain name
        /// not in full system format.
        /// </summary>
        /// <param name="typeName"></param>
        /// <param name="Language"></param>
        /// <returns></returns>
        public static string FixupTypename(TypeDefinition type)
        {
            var typeName = FixupStringTypeName(type.Name);

            if (type.IsGenericInstance || type.IsGenericParameter)
            {
                return(DotnetObject.GetGenericTypeName(type.GetElementType(), GenericTypeNameFormats.TypeName));
            }

            return(typeName);
        }
        /// <summary>
        /// Parses all properties for the type passed
        /// </summary>
        /// <param name="dotnetObject"></param>
        public void ParseEvents(DotnetObject dotnetObject)
        {
            var dotnetType = dotnetObject.TypeDefinition;
            //var dotnetRef = dotnetType.GetElementType();

            var propertyList = new List <ObjectEvent>();

            foreach (var ei in dotnetType.Events)
            {
                if (ei.Name.StartsWith("<"))
                {
                    continue;
                }

                var eiRef = ei.EventType;

                if (NoInheritedMembers && eiRef.DeclaringType != dotnetType)
                {
                    continue;
                }

                var eventObject = new ObjectEvent();
                eventObject.Name = ei.Name;


                eventObject.Type          = ei.EventType.Name;
                eventObject.Scope         = "public";
                eventObject.Signature     = FixupMemberNameForSignature(ei.FullName);
                eventObject.DeclaringType = ei.DeclaringType.FullName;

                eventObject.Syntax = $"{eventObject.Scope} {eventObject.Other} {eventObject.Type} {eventObject.Name}";
                eventObject.Syntax = eventObject.Syntax.Replace("  ", " ");

                propertyList.Add(eventObject);
            }

            dotnetObject.Events.AddRange(propertyList);
        }
        /// <summary>
        /// This method parses comments from C# XML documentation into the appropriate
        /// cHelpText properties.
        /// </summary>
        /// <returns></returns>
        public bool ParseXmlProperties(DotnetObject dotnetObject)
        {
            string      xPath;
            XmlDocument oDom = new XmlDocument();

            try
            {
                oDom.Load("file://" + XmlDocFile);
            }
            catch (Exception ex)
            {
                ErrorMessage = "Unable to load XML Documentation file." + ex.Message;
                return(false);
            }


            XmlNode Match    = null;
            XmlNode SubMatch = null;

            try
            {
                Match = oDom.SelectSingleNode("/doc/members/member[@name='" +
                                              "T:" + dotnetObject.Signature + "']");

                dotnetObject.HelpText = GetNodeValue(Match, "summary") ?? string.Empty;

                dotnetObject.Remarks = GetNodeValue(Match, "remarks");
                dotnetObject.Example = GetExampleCode(Match);

                var dotnetObjectRemarks  = dotnetObject.Remarks.Trim();
                var dotnetObjectHelpText = dotnetObject.HelpText.Trim();


                dotnetObjectHelpText = dotnetObjectHelpText.Replace("\r", "");
                dotnetObjectHelpText = dotnetObjectHelpText.Replace("\n\n", "#$#$#$");
                dotnetObjectHelpText = dotnetObjectHelpText.Replace("\n", " ");
                dotnetObjectHelpText = dotnetObjectHelpText.Replace("#$#$#$", "\r\n\r\n");


                dotnetObject.SeeAlso = FixupSeeAlsoLinks(ref dotnetObjectHelpText) +
                                       FixupSeeAlsoLinks(ref dotnetObjectRemarks);
                dotnetObject.HelpText = dotnetObjectHelpText;
                dotnetObject.Remarks  = dotnetObjectRemarks;

                dotnetObject.Contract = GetContracts(Match);

                Match = null;
            }
            catch (Exception ex)
            {
                string lcError = ex.Message;
            }

            // *** Loop through the methods
            foreach (var method in dotnetObject.AllMethods)
            {
                // *** Strip off empty method parens
                string MethodSignature = method.Signature.Replace("()", "");

                // *** Replace Reference of Reflection for the one use by XML docs
                MethodSignature = MethodSignature.Replace("&", "@");

                if (method.RawParameters == "")
                {
                    xPath = "/doc/members/member[@name='" +
                            "M:" + MethodSignature + "']";  // .cNamespace + "." + loObject.cName + "." + loMethod.cName + "']";
                }
                else
                {
                    xPath = "/doc/members/member[@name='" +
                            "M:" + MethodSignature + "']";
                }

                //							"M:" + loObject.cNamespace + "." + loObject.cName + "." + loMethod.cName +
                //							"(" + loMethod.cRawParameters + ")']";


                try
                {
                    // M:Westwind.Utilities.Encryption.EncryptBytes(System.Byte[],System.String)
                    Match = oDom.SelectSingleNode(xPath);
                    if (Match == null)
                    {
                        continue;
                    }

                    method.HelpText = GetNodeValue(Match, "summary");
                    method.Remarks  = GetNodeValue(Match, "remarks");
                    method.Example  = GetExampleCode(Match);
                    method.Contract = GetContracts(Match);

                    var methodHelpText = method.HelpText;
                    var methodRemarks  = method.Remarks;
                    method.SeeAlso = FixupSeeAlsoLinks(ref methodHelpText) +
                                     FixupSeeAlsoLinks(ref methodRemarks);

                    method.HelpText = methodHelpText;
                    method.Remarks  = methodRemarks;
                    //this.GetNodeValue(Match, "example");

                    // *** Only update returns if the return comment is actually set
                    // *** Otherwise leave the type intact
                    method.ReturnDescription = GetNodeValue(Match, "returns");

                    // *** Parse the parameters
                    string parmDescriptions = "";
                    foreach (var parm in method.ParameterList)
                    {
                        parmDescriptions = parmDescriptions +
                                           "**" + parm + "**  \r\n";

                        SubMatch = Match.SelectSingleNode("param[@name='" + parm + "']");
                        if (SubMatch != null)
                        {
                            string value = SubMatch.InnerText;
                            if (value.Length > 0)
                            {
                                value            = value.Trim(' ', '\t', '\r', '\n');
                                parmDescriptions = parmDescriptions + value + "\r\n\r\n";
                            }
                            else
                            {
                                // empty line
                                parmDescriptions = parmDescriptions + "\r\n";
                            }
                        }
                    }
                    method.DescriptiveParameters = parmDescriptions;

                    string      Exceptions       = "";
                    XmlNodeList ExceptionMatches = null;
                    try
                    {
                        ExceptionMatches = Match.SelectNodes("exception");
                    }
                    catch { }

                    if (ExceptionMatches != null)
                    {
                        foreach (XmlNode Node in ExceptionMatches)
                        {
                            XmlAttribute Ref = Node.Attributes["cref"];
                            if (Ref != null)
                            {
                                Exceptions += "**" + Ref.Value.Replace("T:", "").Replace("!:", "") + "**  \r\n";
                            }
                            if (!string.IsNullOrEmpty(Node.InnerText))
                            {
                                Exceptions += GetNodeValue(Node, "") + "\r\n";
                            }
                            Exceptions += "\r\n";
                        }
                        method.Exceptions = Exceptions.TrimEnd('\r', '\n');
                    }

                    Match = null;
                }
                catch (Exception ex)
                {
                    string lcError = ex.Message;
                }
            }      // for methods

            // Combine properties and fields into a single list
            var propAndFieldList = new List <ObjectProperty>();

            propAndFieldList.AddRange(dotnetObject.Properties);
            propAndFieldList.AddRange(dotnetObject.Fields);

            // *** Loop through the properties and fields in one pass so we can use the same logic
            foreach (var property in propAndFieldList)
            {
                string fieldPrefix = "P:";
                if (property.PropertyMode == PropertyModes.Field)
                {
                    fieldPrefix = "F:";
                }

                xPath = "/doc/members/member[@name='" + fieldPrefix +
                        property.Signature.Replace("()", "") + "']";

                Match = oDom.SelectSingleNode(xPath);

                property.HelpText = GetNodeValue(Match, "summary");
                property.Remarks  = GetNodeValue(Match, "remarks");
                property.Example  = GetExampleCode(Match);
                property.Contract = GetContracts(Match);

                var propertyHelpText = property.HelpText;
                var propertyRemarks  = property.Remarks;
                property.SeeAlso = FixupSeeAlsoLinks(ref propertyHelpText) +
                                   FixupSeeAlsoLinks(ref propertyRemarks);
                property.HelpText = propertyHelpText;
                property.Remarks  = propertyRemarks;

                string value = GetNodeValue(Match, "value");
                if (!string.IsNullOrEmpty(value))
                {
                    property.DefaultValue = value;
                }

                Match = null;
            }      // for properties

            // *** Loop through the fields
            foreach (var evt in dotnetObject.Events)
            {
                string lcFieldPrefix = "E:";

                xPath = "/doc/members/member[@name='" + lcFieldPrefix +
                        evt.Signature + "']";

                Match        = oDom.SelectSingleNode(xPath);
                evt.HelpText = GetNodeValue(Match, "summary");
                evt.Remarks  = GetNodeValue(Match, "remarks");
                evt.Example  = GetExampleCode(Match);

                var evtHelpText = evt.HelpText;
                var evtRemarks  = evt.Remarks;
                evt.SeeAlso = this.FixupSeeAlsoLinks(ref evtHelpText) +
                              this.FixupSeeAlsoLinks(ref evtRemarks);
                evt.HelpText = evtHelpText;
                evt.Remarks  = evtRemarks;

                Match = null;
            }      // for events

            return(true);
        } // ParseXMLProperties (method)
        /// <summary>
        /// This method parses comments from C# XML documentation into the appropriate
        /// cHelpText properties.
        /// </summary>
        /// <returns></returns>
        public bool ParseXmlProperties(DotnetObject PassedObject)
        {
            string       xPath;
            DotnetObject Object;

            XmlDocument oDom = new XmlDocument();

            try
            {
                oDom.Load("file://" + cXmlFilename);
            }
            catch (Exception ex)
            {
                cErrorMsg = "Unable to load XML Documentation file." + ex.Message;
                return(false);
            }

            // *** Get object descriptions
            for (int Objs = 0; Objs < nObjectCount; Objs++)
            {
                XmlNode Match    = null;
                XmlNode SubMatch = null;

                if (PassedObject == null)
                {
                    Object = aObjects[Objs];
                }
                else
                {
                    Object = PassedObject;
                    Objs   = nObjectCount - 1;
                }

                if (PassedObject != null && PassedObject.Name.ToLower() != Object.Name.ToLower())
                {
                    continue;
                }

                try
                {
                    Match = oDom.SelectSingleNode("/doc/members/member[@name='" +
                                                  "T:" + Object.RawSignature + "']");

                    Object.HelpText = GetNodeValue(Match, "summary");

                    Object.Remarks = GetNodeValue(Match, "remarks");
                    Object.Example = GetExampleCode(Match);
                    Object.SeeAlso = FixupSeeAlsoLinks(ref Object.HelpText) +
                                     FixupSeeAlsoLinks(ref Object.Remarks);

                    Object.Contract = GetContracts(Match);

                    Match = null;
                }
                catch (Exception ex)
                {
                    string lcError = ex.Message;
                }

                // *** Loop through the methods
                for (int lnMethods = 0; lnMethods < Object.MethodCount; lnMethods++)
                {
                    ObjectMethod method = Object.Methods[lnMethods];

                    // *** Strip off empty method parens
                    string methodSignature = method.Signature.Replace("()", "");

                    // *** Replace Reference of Reflection for the one use by XML docs
                    methodSignature = methodSignature.Replace("&", "@");

                    if (method.RawParameters == "")
                    {
                        xPath = "/doc/members/member[@name='" +
                                "M:" + methodSignature + "']"; // .cNamespace + "." + loObject.cName + "." + loMethod.cName + "']";
                    }
                    else
                    {
                        xPath = "/doc/members/member[@name='" +
                                "M:" + methodSignature + "']";
                    }

                    //							"M:" + loObject.cNamespace + "." + loObject.cName + "." + loMethod.cName +
                    //							"(" + loMethod.cRawParameters + ")']";


                    try
                    {
                        Match = oDom.SelectSingleNode(xPath);
                        if (Match == null)
                        {
                            continue;
                        }

                        method.HelpText = GetNodeValue(Match, "summary");
                        method.Remarks  = GetNodeValue(Match, "remarks");
                        method.Example  = GetExampleCode(Match);
                        method.Contract = GetContracts(Match);

                        method.SeeAlso = FixupSeeAlsoLinks(ref method.HelpText) +
                                         FixupSeeAlsoLinks(ref method.Remarks);


                        //this.GetNodeValue(Match, "example");

                        // *** Only update returns if the return comment is actually set
                        // *** Otherwise leave the type intact
                        method.ReturnDescription = GetNodeValue(Match, "returns");

                        // *** Parse the parameters
                        string lcParmDescriptions = "";
                        for (int x = 0; x < method.ParameterCount; x++)
                        {
                            string parm = method.ParameterList[x].Trim();
                            lcParmDescriptions = lcParmDescriptions +
                                                 "**" + parm + "**  \r\n";

                            SubMatch = Match.SelectSingleNode("param[@name='" + parm + "']");
                            if (SubMatch != null)
                            {
                                string lcValue = SubMatch.InnerText;
                                if (lcValue.Length > 0)
                                {
                                    lcValue            = lcValue.Trim(' ', '\t', '\r', '\n');
                                    lcParmDescriptions = lcParmDescriptions + lcValue + "\r\n\r\n";
                                }
                                else
                                {
                                    // empty line
                                    lcParmDescriptions = lcParmDescriptions + "\r\n";
                                }
                            }
                        }
                        method.DescriptiveParameters = lcParmDescriptions;

                        string      Exceptions       = "";
                        XmlNodeList ExceptionMatches = null;
                        try
                        {
                            ExceptionMatches = Match.SelectNodes("exception");
                        }
                        catch {; }

                        if (ExceptionMatches != null)
                        {
                            foreach (XmlNode Node in ExceptionMatches)
                            {
                                XmlAttribute Ref = Node.Attributes["cref"];
                                if (Ref != null)
                                {
                                    Exceptions += "**" + Ref.Value.Replace("T:", "").Replace("!:", "") + "**  \r\n";
                                }
                                if (!string.IsNullOrEmpty(Node.InnerText))
                                {
                                    Exceptions += GetNodeValue(Node, "") + "\r\n";
                                }
                                Exceptions += "\r\n";
                            }
                            method.Exceptions = Exceptions.TrimEnd('\r', '\n');
                        }

                        Match = null;
                    }
                    catch (Exception ex)
                    {
                        string lcError = ex.Message;
                    }
                }  // for methods

                // *** Loop through the properties
                for (int lnFields = 0; lnFields < Object.PropertyCount; lnFields++)
                {
                    ObjectProperty property = Object.Properties[lnFields];

                    string fieldPrefix = "F:";
                    if (property.FieldOrProperty != "Field")
                    {
                        fieldPrefix = "P:";
                    }

                    xPath = "/doc/members/member[@name='" + fieldPrefix +
                            property.Signature + "']";

                    Match = oDom.SelectSingleNode(xPath);

                    property.HelpText = GetNodeValue(Match, "summary");
                    property.Remarks  = GetNodeValue(Match, "remarks");
                    property.Example  = GetExampleCode(Match);
                    property.Contract = GetContracts(Match);

                    property.SeeAlso = FixupSeeAlsoLinks(ref property.HelpText) +
                                       FixupSeeAlsoLinks(ref property.Remarks);


                    string value = GetNodeValue(Match, "value");
                    if (!string.IsNullOrEmpty(value))
                    {
                        property.DefaultValue = value;
                    }

                    Match = null;
                }  // for properties

                // *** Loop through the fields
                for (int lnFields = 0; lnFields < Object.EventCount; lnFields++)
                {
                    ObjectEvent loEvent = Object.Events[lnFields];

                    string lcFieldPrefix = "E:";

                    xPath = "/doc/members/member[@name='" + lcFieldPrefix +
                            loEvent.Signature + "']";

                    Match            = oDom.SelectSingleNode(xPath);
                    loEvent.HelpText = GetNodeValue(Match, "summary");
                    loEvent.Remarks  = GetNodeValue(Match, "remarks");
                    loEvent.Example  = GetExampleCode(Match);

                    loEvent.SeeAlso = FixupSeeAlsoLinks(ref loEvent.HelpText) +
                                      FixupSeeAlsoLinks(ref loEvent.Remarks);

                    Match = null;
                } // for events
            }     // for objects

            return(true);
        } // ParseXMLProperties (method)
        /// <summary>
        /// Internal method that's used to parse the currently selected object
        /// parsing methods and properties and the various object properties including
        /// object inheritance etc.
        /// </summary>
        /// <param name="dotnetObject"></param>
        /// <param name="type"></param>
        /// <param name="dontParseMethods"></param>
        protected void ParseObject(DotnetObject dotnetObject, Type type, bool dontParseMethods)
        {
            // *** Pass down high level options
            dotnetObject.Name        = type.Name;
            dotnetObject.RawTypeName = type.Name;

            dotnetObject.Syntax = cSyntax;
            dotnetObject.RetrieveDeclaredMembersOnly = RetrieveDeclaredMembersOnly;

            bool IsVb = cSyntax.StartsWith("VB");

            // *** If we have a generic type strip off
            if (type.IsGenericType)
            {
                dotnetObject.Name = DotnetObject.GetGenericTypeName(type, GenericTypeNameFormats.TypeName);
            }

            dotnetObject.FormattedName = dotnetObject.TypeNameForLanguage(dotnetObject.Name);


            // *** Parse basic type features
            if (type.IsPublic || type.IsNestedPublic)
            {
                dotnetObject.Scope = "public";
            }
            if (!type.IsVisible)
            {
                dotnetObject.Scope    = "internal";
                dotnetObject.Internal = true;
            }
            else if (type.IsNotPublic || type.IsNestedPrivate)
            {
                dotnetObject.Scope = "private";
            }

            if (IsVb)
            {
                dotnetObject.Scope = StringUtils.ProperCase(dotnetObject.Scope);
            }

            if (type.IsSealed && type.IsAbstract)
            {
                dotnetObject.Other = "static";
            }
            else
            {
                if (type.IsSealed)
                {
                    if (IsVb)
                    {
                        dotnetObject.Other = "NotInheritable";
                    }
                    else
                    {
                        dotnetObject.Other = "sealed";
                    }
                }

                if (type.IsAbstract)
                {
                    if (IsVb)
                    {
                        dotnetObject.Other = "MustInherit";
                    }
                    else
                    {
                        dotnetObject.Other += "abstract";
                    }
                }
            }

            // *** Get the type 'signature'
            dotnetObject.Signature    = type.FullName;
            dotnetObject.RawSignature = dotnetObject.Signature;

            //// *** Generic Type: Replace signature wwBusiness`1 with wwBusiness<EntityType> (cName)
            //if (loType.IsGenericType)
            //    loObject.cSignature = loObject.cSignature.Substring(0, loObject.cSignature.LastIndexOf(".")+1) + loObject.cName;

            dotnetObject.Namespace = type.Namespace;
            dotnetObject.Assembly  = type.Assembly.CodeBase;
            dotnetObject.Assembly  = dotnetObject.Assembly.Substring(dotnetObject.Assembly.LastIndexOf("/") + 1);

            dotnetObject.Type = "class";
            if (type.IsInterface)
            {
                dotnetObject.Type = "interface";
            }
            else if (type.IsEnum)
            {
                dotnetObject.Type = "enum";
            }
            else if (type.IsValueType)
            {
                dotnetObject.Type = "struct";
            }

            // *** Figure out the base type and build inheritance tree
            // *** for this class
            if (type.BaseType != null)
            {
                string BaseTypeName = null;
                if (type.BaseType.IsGenericType)
                {
                    //BaseTypeName = DotnetObject.GetGenericTypeName(type.BaseType, GenericTypeNameFormats.TypeName);
                    //else
                    BaseTypeName = type.BaseType.Name;
                }

                dotnetObject.InheritsFrom = dotnetObject.TypeNameForLanguage(BaseTypeName);

                if (dotnetObject.InheritsFrom == "MulticastDelegate" || dotnetObject.InheritsFrom == "Delegate")
                {
                    dotnetObject.Type = "delegate";
                }

                Type[] Implementations = type.GetInterfaces();

                if (Implementations != null)
                {
                    foreach (Type Implementation in Implementations)
                    {
                        // *** This will work AS LONG AS THE INTERFACE HAS AT LEAST ONE MEMBER!
                        // *** This will give not show an 'empty' placeholder interface
                        // *** Can't figure out a better way to do this...
                        InterfaceMapping im = type.GetInterfaceMap(Implementation);
                        if (im.TargetMethods.Length > 0 && im.TargetMethods[0].DeclaringType == type)
                        {
                            if (Implementation.IsGenericType)
                            {
                                dotnetObject.Implements += DotnetObject.GetGenericTypeName(Implementation, GenericTypeNameFormats.TypeName) + ",";
                            }
                            else
                            {
                                dotnetObject.Implements += Implementation.Name + ",";
                            }
                        }
                    }
                    if (dotnetObject.Implements != "")
                    {
                        dotnetObject.Implements = dotnetObject.Implements.TrimEnd(',');
                    }
                }


                // *** Create the Inheritance Tree
                List <string> Tree    = new List <string>();
                Type          Current = type;
                while (Current != null)
                {
                    if (Current.IsGenericType)
                    {
                        Tree.Add(dotnetObject.TypeNameForLanguage(DotnetObject.GetGenericTypeName(Current, GenericTypeNameFormats.FullTypeName)));
                    }
                    else
                    {
                        Tree.Add(Current.FullName);
                    }

                    Current = Current.BaseType;
                }

                // *** Walk our list backwards to build the string
                for (int z = Tree.Count - 1; z >= 0; z--)
                {
                    dotnetObject.InheritanceTree += Tree[z] + "\r\n";
                }
            }

            if (!dontParseMethods)
            {
                //dotnetObject.LoadMethods(type);
                //dotnetObject.LoadProperties(type);
                //dotnetObject.LoadEvents(type);
            }
        }
        /// <summary>
        /// Parses an object by name and sets the oObject
        /// member with the result.
        /// </summary>
        /// <param name="className">Class name to search</param>
        /// <returns></returns>
        public bool GetObject(string className)
        {
            lError = false;

            bool   GenericType = (className.IndexOf("<") > -1);
            string BaseType    = className;

            if (GenericType)
            {
                BaseType = className.Substring(0, className.IndexOf("<"));
            }

            if (aObjects == null)
            {
                if (GetAllObjects(true) == 0 && lError)
                {
                    return(false);
                }
            }

            for (int x = 0; x < aXObjects.Length; x++)
            {
                Type loType = aXObjects[x];

                // Check for Obsolete members
                IList <CustomAttributeData> attrs = CustomAttributeData.GetCustomAttributes(loType);
                bool isObsolete = false;
                foreach (CustomAttributeData attr in attrs)
                {
                    string name = attr.ToString();
                    if (name.Contains("ObsoleteAttribute("))
                    {
                        isObsolete = true;
                        break;
                    }
                }

                // skip over this type
                if (isObsolete)
                {
                    continue;
                }

                // *** Check for matching type or generic type
                if (!(loType.Name.ToLower() == className.ToLower() ||
                      (GenericType && loType.Name.ToLower().StartsWith(BaseType.ToLower() + "`")))
                    )
                {
                    continue;
                }

                oObject             = new DotnetObject();
                oObject.Name        = loType.Name;
                oObject.RawTypeName = loType.Name;

                oObject.Syntax = cSyntax;
                oObject.RetrieveDeclaredMembersOnly = RetrieveDeclaredMembersOnly;

                ParseObject(oObject, loType, false);
            }

            if (cXmlFilename.Length > 0)
            {
                ParseXmlProperties(oObject);
            }

            return(true);
        }
        /// <summary>
        /// Gets all objects into the aObjects array and parses all method/properties into the subarrays.
        /// </summary>
        /// <param name="DontParseMethods">if true methods and properties are not parsed</param>
        /// <returns></returns>
        public int GetAllObjects(bool DontParseMethods)
        {
            lError = false;

            Assembly assembly;

            try
            {
                // Load up full assembly
                AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
                assembly = Assembly.LoadFrom(Filename);

                // Load up reflection only assembly - fails with runtime version fixups
                //AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += CurrentDomain_ReflectionOnlyAssemblyResolve;
                //assembly = System.Reflection.Assembly.ReflectionOnlyLoadFrom(this.cFilename);
            }
            catch (Exception ex)
            {
                lError    = true;
                cErrorMsg = String.Format("Unable to load assembly.\r\n" +
                                          "Typically this is caused by missing dependent assemblies\r\n" +
                                          "or an assembly compiled using a runtime higher than this version: {0}.\r\n\r\n" +
                                          "Raw Error:\r\n{1}", Environment.Version.ToString(), ex.GetBaseException().Message);
                return(0);
            }

            try
            {
                aXObjects = assembly.GetTypes();
            }
            catch (Exception ex)
            {
                lError    = true;
                cErrorMsg = String.Format("Unable to load types from assembly.\r\n" +
                                          "Typically this is caused by missing dependent assemblies\r\n" +
                                          "or an assembly compiled using a runtime higher than this version: {0}.\r\n\r\n" +
                                          "Raw Error:\r\n{1}", Environment.Version.ToString(), ex.GetBaseException().Message);

                return(0);
            }


            try
            {
                int Count = aXObjects.Length;
                if (Count == 0)
                {
                    return(0);
                }

                nObjectCount = Count;
                aObjects     = new DotnetObject[Count];


                for (int x = 0; x < aXObjects.Length; x++)
                {
                    Type type = aXObjects[x];
                    aObjects[x] = new DotnetObject();
                    ParseObject(aObjects[x], type, DontParseMethods);
                }

                if (!DontParseMethods && cXmlFilename.Length > 0)
                {
                    ParseXmlProperties(null);
                }

                ArrayList al = new ArrayList(aObjects);
                al.Sort();
                aObjects = al.ToArray(typeof(DotnetObject)) as DotnetObject[];

                return(Count);
            }
            catch (Exception ex)
            {
                lError    = true;
                cErrorMsg = ex.Message + "\r\n\r\n" +
                            ex.StackTrace + "\r\n";
                return(0);
            }
        }
        /// <summary>
        /// Parses all fields for the type passed
        /// </summary>
        /// <param name="dotnetObject"></param>
        public void ParseFields(DotnetObject dotnetObject)
        {
            var dotnetType = dotnetObject.TypeDefinition;
            //var dotnetRef = dotnetType.GetElementType();

            var propertyList = new List <ObjectProperty>();

            foreach (var pi in dotnetType.Fields)
            {
                if (pi.Name.StartsWith("<"))
                {
                    continue;
                }

                var piRef = pi.FieldType;

                if (NoInheritedMembers && piRef.DeclaringType != dotnetType)
                {
                    continue;
                }

                var prop = new ObjectProperty();
                prop.Name         = FixupStringTypeName(pi.FieldType.Name);
                prop.PropertyMode = PropertyModes.Field;

                if (pi.IsStatic)
                {
                    prop.Static = pi.IsStatic;
                    prop.Other += "static ";
                }

                if (!string.IsNullOrEmpty(prop.Other))
                {
                    prop.Other = prop.Other.Trim();
                }

                // *** Parse basic type features
                if (pi.IsPublic)
                {
                    prop.Scope = "public";
                }

                // TODO: Internal Protected needs to be addressed
                else if (pi.IsAssembly || pi.IsFamilyOrAssembly)
                {
                    prop.Scope    = "internal";
                    prop.Internal = true;
                }
                else if (pi.IsPrivate)
                {
                    prop.Scope = "private";
                }

                if (!piRef.IsGenericInstance)
                {
                    prop.Type = FixupStringTypeName(pi.Name);
                }
                else
                {
                    prop.Type = DotnetObject.GetGenericTypeName(pi.FieldType, GenericTypeNameFormats.TypeName);
                }

                prop.Syntax        = $"{prop.Scope} {prop.Other} {prop.Type} {prop.Name}" + prop.Name;
                prop.Syntax        = prop.Syntax.Replace("  ", " ");
                prop.Signature     = prop.Signature = FixupMemberNameForSignature(pi.FullName);
                prop.DeclaringType = pi.DeclaringType.FullName;

                propertyList.Add(prop);
            }

            dotnetObject.Properties.AddRange(propertyList);
        }
        /// <summary>
        /// Parses all properties for the type passed
        /// </summary>
        /// <param name="dotnetObject"></param>
        public void ParseProperties(DotnetObject dotnetObject)
        {
            var dotnetType = dotnetObject.TypeDefinition;
            //var dotnetRef = dotnetType.GetElementType();

            var propertyList = new List <ObjectProperty>();

            foreach (var pi in dotnetType.Properties)
            {
                var piRef = pi.PropertyType;

                //if (NoInheritedMembers && piRef.DeclaringType != dotnetType)
                //    continue;

                var prop = new ObjectProperty();
                prop.Name = pi.Name;
                if (prop.Name.StartsWith("<"))
                {
                    continue;
                }

                prop.Classname = pi.DeclaringType.Name;

                prop.PropertyMode = PropertyModes.Property;

                MethodDefinition mi;
                if (pi.GetMethod != null)
                {
                    mi = pi.GetMethod;
                }
                else
                {
                    mi = pi.SetMethod;
                }

                if (mi.IsPrivate)
                {
                    return;
                }


                if (mi.IsAbstract)
                {
                    prop.Other += "abstract ";
                }

                if (mi.IsVirtual && !mi.IsAbstract)
                {
                    prop.Other += "virtual ";
                }

                if (mi.IsStatic)
                {
                    prop.Static = mi.IsStatic;
                    prop.Other += "static ";
                }
                if (mi.IsFinal)
                {
                    prop.Other += "sealed ";
                }

                if (pi.SetMethod != null && pi.GetMethod != null)
                {
                }
                else if (pi.SetMethod == null)
                {
                    prop.Other += "readonly ";
                }
                else if (pi.GetMethod == null)
                {
                    prop.Other += "writeonly ";
                }

                if (!string.IsNullOrEmpty(prop.Other))
                {
                    prop.Other = prop.Other.Trim();
                }

                // *** Parse basic type features
                if (mi.IsPublic)
                {
                    prop.Scope = "public";
                }

                // TODO: Internal Protected needs to be addressed
                else if (mi.IsAssembly || mi.IsFamilyOrAssembly)
                {
                    prop.Scope    = "internal";
                    prop.Internal = true;
                }
                else if (mi.IsPrivate)
                {
                    prop.Scope = "private";
                }

                if (!piRef.IsGenericInstance)
                {
                    prop.Type = FixupStringTypeName(pi.PropertyType.Name);
                }
                else
                {
                    prop.Type = DotnetObject.GetGenericTypeName(pi.PropertyType, GenericTypeNameFormats.TypeName);
                }


                prop.Syntax        = $"{prop.Scope} {prop.Other} {prop.Type} {prop.Name}";
                prop.Syntax        = prop.Syntax.Replace("  ", " ");
                prop.Signature     = FixupMemberNameForSignature(pi.FullName);
                prop.DeclaringType = pi.DeclaringType.FullName;

                propertyList.Add(prop);
            }

            dotnetObject.Properties.AddRange(propertyList);
        }
        private void ParseMethodsOnType(DotnetObject dotnetObject, Collection <MethodDefinition> methods, TypeDefinition dotnetType)
        {
            var methodList = new List <ObjectMethod>();

            foreach (var mi in methods)
            {
                var meth  = new ObjectMethod();
                var miRef = mi.GetElementMethod();

                if (NoInheritedMembers && miRef.DeclaringType != dotnetType)
                {
                    continue;
                }

                meth.Name = mi.Name;
                if (meth.Name.StartsWith("<") || mi.IsGetter || mi.IsSetter || mi.IsAddOn || mi.IsRemoveOn || mi.IsPrivate)
                {
                    continue;
                }


                meth.Classname = mi.DeclaringType.Name;

                if (mi.IsConstructor)
                {
                    // no static or base class constructors
                    if (mi.IsStatic || mi.DeclaringType.FullName != dotnetObject.TypeDefinition.FullName)
                    {
                        continue; // don't document static constructors
                    }
                    meth.IsConstructor = true;
                    meth.Name          = dotnetObject.Name;
                }

                if (mi.IsPublic)
                {
                    meth.Scope = "public";
                }
                // TODO: Internal Protected needs to be addressed
                else if (mi.IsAssembly || mi.IsFamilyOrAssembly)
                {
                    meth.Scope    = "internal";
                    meth.Internal = true;
                }
                else if (mi.IsPrivate)
                {
                    meth.Scope = "private";
                }

                if (mi.IsAbstract)
                {
                    meth.Other += "abstract ";
                }

                if (mi.IsVirtual && !mi.IsAbstract)
                {
                    meth.Other += "virtual ";
                }

                if (mi.IsStatic)
                {
                    meth.Static = mi.IsStatic;
                    meth.Other += "static ";
                }

                if (mi.IsFinal)
                {
                    meth.Other += "sealed ";
                }

                if (mi.HasGenericParameters || mi.ContainsGenericParameter)
                {
                    meth.GenericParameters = "<";
                    var genericParms = miRef.GenericParameters;
                    foreach (var genericArg in genericParms)
                    {
                        meth.GenericParameters += genericArg.Name + ",";
                    }

                    meth.GenericParameters  = meth.GenericParameters.TrimEnd(',');
                    meth.GenericParameters += ">";
                    if (meth.GenericParameters == "<>")
                    {
                        meth.GenericParameters = "";
                    }
                }

                foreach (var parm in mi.Parameters)
                {
                    var methodParm = new MethodParameter();
                    methodParm.Name = parm.Name;
                    if (methodParm.Name.EndsWith("&"))
                    {
                        methodParm.Other = "ref ";
                        methodParm.Name  = methodParm.Name.TrimEnd('&');
                    }

                    methodParm.ShortTypeName = FixupStringTypeName(parm.ParameterType.Name);
                    if (parm.ParameterType.IsGenericInstance)
                    {
                        methodParm.ShortTypeName =
                            DotnetObject.GetGenericTypeName(parm.ParameterType.GetElementType(),
                                                            GenericTypeNameFormats.TypeName);
                    }


                    methodParm.Type = parm.ParameterType.FullName;


                    meth.ParameterList.Add(methodParm);
                }

                meth.ReturnType = mi.ReturnType.FullName;

                var simpleRetName = mi.ReturnType.Name;
                if (!mi.ReturnType.IsGenericParameter)
                {
                    simpleRetName = FixupStringTypeName(simpleRetName);
                }

                var sbSyntax = new StringBuilder();
                sbSyntax.Append($"{dotnetObject.Scope} {dotnetObject.Other} {simpleRetName} {meth.Name}{meth.GenericParameters}(");

                var parmCounter = 0;
                foreach (var parm in meth.ParameterList)
                {
                    sbSyntax.Append($"{parm.ShortTypeName} {parm.Name}, ");
                    parmCounter++;
                    if (parmCounter % 2 == 0)
                    {
                        sbSyntax.Append("\r\n\t\t\t");
                    }
                }

                meth.Syntax = sbSyntax.ToString();
                meth.Syntax = meth.Syntax.TrimEnd(' ', ',', '\r', '\n', '\t') + ")";
                meth.Syntax = meth.Syntax.Replace("   ", " ").Replace("  ", " ");

                if (meth.IsConstructor)
                {
                    meth.Signature = mi.DeclaringType.FullName + ".#ctor";
                }

                string parameters    = "";
                string rawParameters = "";


                meth.Signature = mi.FullName;

                // strip off return type
                var idx = meth.Signature.IndexOf(' ');
                if (idx > -1)
                {
                    meth.Signature = meth.Signature.Substring(idx).TrimStart();
                }

                // fix up ctor
                meth.Signature = meth.Signature.Replace("::.ctor", ".#ctor");

                // fix up object member syntax and double conversions
                meth.Signature = meth.Signature
                                 .Replace("::", ".")
                                 .Replace("..", ".")
                                 .Trim();

                // fix up parameters
                if (meth.Signature.EndsWith("()"))
                {
                    // no parms has no parens ie. .method
                    meth.Signature = meth.Signature.Substring(0, meth.Signature.Length - 2);
                }
                else
                {
                    // fix up parameters for generics
                    // from:  .method(System.Collections.Generic.IDictionary`2(System.String,System.Object),System.String)
                    // to:    .method(System.Collections.Generic.IDictionary{System.String,System.Object},System.String)
                    var origParms = StringUtils.ExtractString(meth.Signature, "(", ")", returnDelimiters: true);
                    var newParms  = origParms;
                    if (origParms.Contains("`"))
                    {
                        var regEx   = new Regex("`.*?<(.*?)>");
                        var matches = regEx.Matches(meth.Signature);
                        foreach (Match match in matches)
                        {
                            var orig = match.Value;
                            var type = match.Groups[1].Value;
                            newParms = newParms.Replace(orig, "{" + type + "}");
                        }
                    }

                    if (!newParms.Equals(origParms))
                    {
                        meth.Signature = meth.Signature.Replace(origParms, newParms);
                    }
                }

                methodList.Add(meth);
            }

            dotnetObject.AllMethods.AddRange(methodList
                                             .OrderBy(ml => !ml.IsConstructor)
                                             .ThenBy(ml => ml.Name.ToLowerInvariant()));
        }
        /// <summary>
        /// Parses an object based on a  Mono.Cecil type definition
        /// </summary>
        /// <param name="type"></param>
        /// <param name="dontParseMembers"></param>
        /// <returns></returns>
        public DotnetObject ParseObject(TypeDefinition type, bool dontParseMembers = false)
        {
            if (type.Name.StartsWith("<"))
            {
                return(null);
            }

            var dotnetObject = new DotnetObject
            {
                Name           = type.Name,
                RawTypeName    = type.Name,
                Assembly       = type.Module.Assembly.Name.Name,
                TypeDefinition = type
            };

            // *** If we have a generic type strip off
            if (type.HasGenericParameters)
            {
                dotnetObject.Name = DotnetObject.GetGenericTypeName(type, GenericTypeNameFormats.TypeName);
            }

            dotnetObject.FormattedName = FixupStringTypeName(dotnetObject.Name);

            // *** Parse basic type features
            if (type.IsPublic || type.IsNestedPublic)
            {
                dotnetObject.Scope = "public";
            }
            else if (type.IsNestedFamilyOrAssembly || type.IsNestedFamily)
            {
                dotnetObject.Scope    = "internal";
                dotnetObject.Internal = true;
            }
            else if (type.IsNotPublic || type.IsNestedPrivate)
            {
                dotnetObject.Scope = "private";
            }

            if (type.IsSealed && type.IsAbstract)
            {
                dotnetObject.Other = "static";
            }
            else
            {
                if (type.IsSealed && !type.IsEnum)
                {
                    dotnetObject.Other = "sealed";
                }

                if (type.IsAbstract && !type.IsInterface)
                {
                    dotnetObject.Other += "abstract";
                }
            }


            dotnetObject.IsInterface = type.IsInterface;
            dotnetObject.IsAbstract  = type.IsAbstract;

            dotnetObject.Namespace = type.Namespace;
            dotnetObject.Signature = type.FullName;

            dotnetObject.Type = "class";
            if (type.IsInterface)
            {
                dotnetObject.Type = "interface";
            }
            else if (type.IsEnum)
            {
                dotnetObject.Type = "enum";
            }
            else if (type.IsValueType)
            {
                dotnetObject.Type = "struct";
            }

            if (type.BaseType != null)
            {
                string baseTypeName = null;
                if (type.BaseType.HasGenericParameters || type.BaseType.IsGenericInstance)
                {
                    baseTypeName = DotnetObject.GetGenericTypeName(type.BaseType, GenericTypeNameFormats.TypeName);
                }
                else
                {
                    baseTypeName = type.BaseType.Name;
                }

                if (baseTypeName == "Object" || baseTypeName == "Enum" || baseTypeName == "Delegate")
                {
                    dotnetObject.InheritsFrom = null;
                }
                else
                {
                    dotnetObject.InheritsFrom = FixupStringTypeName(baseTypeName);
                }


                if (dotnetObject.InheritsFrom == "MulticastDelegate" || dotnetObject.InheritsFrom == "Delegate")
                {
                    dotnetObject.Type = "delegate";
                }

                var implentations = type.Interfaces; //.GetInterfaces();

                if (implentations != null)
                {
                    foreach (var implementation in implentations)
                    {
                        // *** This will work AS LONG AS THE INTERFACE HAS AT LEAST ONE MEMBER!
                        // *** This will give not show an 'empty' placeholder interface
                        // *** Can't figure out a better way to do this...
                        //InterfaceMapping im = type.GetInterfaceMap(implementation);
                        //if (im.TargetMethods.Length > 0 && im.TargetMethods[0].DeclaringType == type)
                        //{
                        if (implementation.InterfaceType.IsGenericInstance)
                        {
                            dotnetObject.Implements += DotnetObject.GetGenericTypeName(implementation.InterfaceType, GenericTypeNameFormats.TypeName) + ",";
                        }
                        else
                        {
                            dotnetObject.Implements += implementation.InterfaceType.Name + ",";
                        }
                        //}
                    }
                    if (!string.IsNullOrEmpty(dotnetObject.Implements))
                    {
                        dotnetObject.Implements = dotnetObject.Implements.TrimEnd(',');
                    }
                }


                // *** Create the Inheritance Tree
                List <string> Tree    = new List <string>();
                var           current = type;
                while (current != null)
                {
                    if (current.IsGenericInstance)
                    {
                        Tree.Insert(0, FixupStringTypeName(DotnetObject.GetGenericTypeName(current, GenericTypeNameFormats.FullTypeName)));
                    }
                    else
                    {
                        Tree.Insert(0, current.FullName);
                    }

                    var tref = current.BaseType as TypeReference;
                    if (tref == null)
                    {
                        break;
                    }

                    var tdef = new TypeDefinition(tref.Namespace, tref.Name, Mono.Cecil.TypeAttributes.Class, tref);
                    if (current.FullName == tdef.FullName)
                    {
                        break;
                    }

                    current = tdef;
                }


                StringBuilder sb = new StringBuilder();

                // *** Walk our list backwards to build the string
                foreach (var ti in Tree)
                {
                    sb.AppendLine(ti + "  ");
                }
                dotnetObject.InheritanceTree = sb.ToString();
            }

            dotnetObject.Syntax = $"{dotnetObject.Scope} {dotnetObject.Other} {dotnetObject.Type} {dotnetObject.Name}"
                                  .Replace("   ", " ")
                                  .Replace("  ", " ");

            if (!string.IsNullOrEmpty(dotnetObject.InheritsFrom))
            {
                dotnetObject.Syntax += " : " + dotnetObject.InheritsFrom;
            }

            dotnetObject.Assembly = type.Module.FileName;
            dotnetObject.Assembly = Path.GetFileName(dotnetObject.Assembly);

            if (!dontParseMembers)
            {
                ParseMethods(dotnetObject);
                ParseFields(dotnetObject);
                ParseProperties(dotnetObject);
                ParseEvents(dotnetObject);
            }

            if (ParseXmlDocumentation)
            {
                var docFile = Path.ChangeExtension(AssemblyFilename, "xml");
                if (File.Exists(docFile))
                {
                    var parser = new XmlDocumentationParser(docFile);
                    if (!parser.ParseXmlProperties(dotnetObject))
                    {
                        SetError(parser.ErrorMessage);
                    }
                }
            }

            return(dotnetObject);
        }