/// <summary>
        /// Add a known type to the list. Args is (.net type/cpp type)
        /// </summary>
        /// <param name="typeName"></param>
        public static void AddMethod(string typeName, string methodName, string cppMethodName, Tuple <string, string>[] args = null, string[] includeFiles = null)
        {
            var kt = new KnownTypeInfo()
            {
                Name = typeName
            };
            var ourArgs = new KnownTypeInfo.MechodArg[0];

            if (args != null)
            {
                ourArgs = (from t in args
                           select new KnownTypeInfo.MechodArg()
                {
                    Type = t.Item1,
                    CPPType = t.Item2
                }).ToArray();
            }

            var incfiles = includeFiles;

            if (incfiles == null)
            {
                incfiles = new string[0];
            }

            kt.Methods = new KnownTypeInfo.MethodInfo[] { new KnownTypeInfo.MethodInfo()
                                                          {
                                                              Name = methodName, CPPName = cppMethodName, Arguments = ourArgs, IncludeFiles = incfiles
                                                          } };
            gSetTypes.Add(kt);
        }
        /// <summary>
        /// Merge a type in with another type we already have.
        /// </summary>
        /// <param name="kt"></param>
        private void Merge(KnownTypeInfo kt)
        {
            Init();

            var already = (from k in _knownTypes
                           where k.Name == kt.Name
                           select k).FirstOrDefault();

            if (already == null)
            {
                _knownTypes.Add(kt);
            }
            else
            {
                List <KnownTypeInfo.MethodInfo> methods = new List <KnownTypeInfo.MethodInfo>(already.Methods);
                methods.AddRange(kt.Methods);
                already.Methods = methods.ToArray();
            }
        }
        /// <summary>
        /// Parse a stream from a file (or whatever) for function definitions and add them. Don't supersede ones that are already there, but
        /// allow duplicates.
        /// </summary>
        /// <param name="stringReader"></param>
        internal void Parse(TextReader stringReader)
        {
            ///
            /// Get the "good" lines
            ///

            var goodLines = from l in ReadLinesAsIterator(stringReader)
                            let ltrm = l.Trim()
                                       where !ltrm.StartsWith("#") && !string.IsNullOrWhiteSpace(ltrm)
                                       select ltrm;

            ///
            /// Is the format good enough that we can split things up?
            ///

            Regex funcFinder = new Regex("(?<class>[^\\s]+)\\s+(?<netfunc>[^\\s\\(]+)\\s*\\((?<netargs>[^\\)]+)\\)\\s*=>\\s*(?<cppfunc>[^\\s\\(]+)\\s*\\((?<cppargs>[^\\)]+)\\)");

            string[] includfiles = new string[0];

            foreach (var line in goodLines)
            {
                if (line.StartsWith("include:"))
                {
                    var files = from l in line.Substring(8).Split(' ')
                                let lstuff = l.Trim()
                                             where !string.IsNullOrWhiteSpace(lstuff)
                                             select l;
                    includfiles = files.ToArray();
                    continue;
                }

                var m = funcFinder.Match(line);
                if (!m.Success)
                {
                    throw new InvalidDataException("Unable to interpret line '" + line + "'");
                }

                var netargs = ParseArgumentListTokens(m.Groups["netargs"].Value);

                var cppargs = ParseArgumentListTokens(m.Groups["cppargs"].Value);

                if (cppargs.Length != netargs.Length)
                {
                    throw new InvalidDataException("Arguments for cpp and net are not the same in line '" + line + "'");
                }

                ///
                /// Finally, ready to create the mapping!
                ///

                var kt = new KnownTypeInfo()
                {
                    Name    = m.Groups["class"].Value,
                    Methods = new KnownTypeInfo.MethodInfo[] { new KnownTypeInfo.MethodInfo()
                                                               {
                                                                   Name         = m.Groups["netfunc"].Value,
                                                                   CPPName      = m.Groups["cppfunc"].Value,
                                                                   Arguments    = (from a in netargs.Zip(cppargs, (n, c) => new KnownTypeInfo.MechodArg()
                            {
                                CPPType = c, Type = n
                            }) select a).ToArray(),
                                                                   IncludeFiles = includfiles
                                                               } }
                };

                Merge(kt);
            }
        }
        /// <summary>
        /// Merge a type in with another type we already have.
        /// </summary>
        /// <param name="kt"></param>
        private void Merge(KnownTypeInfo kt)
        {
            Init();

            var already = (from k in _knownTypes
                           where k.Name == kt.Name
                           select k).FirstOrDefault();

            if (already == null)
            {
                _knownTypes.Add(kt);
            }
            else
            {
                List<KnownTypeInfo.MethodInfo> methods = new List<KnownTypeInfo.MethodInfo>(already.Methods);
                methods.AddRange(kt.Methods);
                already.Methods = methods.ToArray();
            }

        }
        /// <summary>
        /// Parse a stream from a file (or whatever) for function definitions and add them. Don't supersede ones that are already there, but
        /// allow duplicates.
        /// </summary>
        /// <param name="stringReader"></param>
        internal void Parse(TextReader stringReader)
        {
            ///
            /// Get the "good" lines
            /// 

            var goodLines = from l in ReadLinesAsIterator(stringReader)
                            let ltrm = l.Trim()
                            where !ltrm.StartsWith("#") && !string.IsNullOrWhiteSpace(ltrm)
                            select ltrm;

            ///
            /// Is the format good enough that we can split things up?
            /// 

            Regex funcFinder = new Regex("(?<class>[^\\s]+)\\s+(?<netfunc>[^\\s\\(]+)\\s*\\((?<netargs>[^\\)]+)\\)\\s*=>\\s*(?<cppfunc>[^\\s\\(]+)\\s*\\((?<cppargs>[^\\)]+)\\)");
            string[] includfiles = new string[0];

            foreach (var line in goodLines)
            {
                if (line.StartsWith("include:"))
                {
                    var files = from l in line.Substring(8).Split(' ')
                                let lstuff = l.Trim()
                                where !string.IsNullOrWhiteSpace(lstuff)
                                select l;
                    includfiles = files.ToArray();
                    continue;
                }

                var m = funcFinder.Match(line);
                if (!m.Success)
                    throw new InvalidDataException("Unable to interpret line '" + line + "'");

                var netargs = ParseArgumentListTokens(m.Groups["netargs"].Value);

                var cppargs = ParseArgumentListTokens(m.Groups["cppargs"].Value);

                if (cppargs.Length != netargs.Length)
                {
                    throw new InvalidDataException("Arguments for cpp and net are not the same in line '" + line + "'");
                }

                ///
                /// Finally, ready to create the mapping!
                /// 

                var kt = new KnownTypeInfo()
                {
                    Name = m.Groups["class"].Value,
                    Methods = new KnownTypeInfo.MethodInfo[] {new KnownTypeInfo.MethodInfo() {
                         Name = m.Groups["netfunc"].Value,
                         CPPName = m.Groups["cppfunc"].Value,
                         Arguments = (from a in netargs.Zip(cppargs, (n, c) => new KnownTypeInfo.MechodArg() { CPPType = c, Type = n}) select a).ToArray(),
                         IncludeFiles = includfiles
                     }
                     }
                };

                Merge(kt);
            }

        }
        /// <summary>
        /// Add a known type to the list. Args is (.net type/cpp type)
        /// </summary>
        /// <param name="typeName"></param>
        public static void AddMethod(string typeName, string methodName, string cppMethodName, Tuple<string, string>[] args = null, string[] includeFiles = null)
        {
            var kt = new KnownTypeInfo() { Name = typeName };
            var ourArgs = new KnownTypeInfo.MechodArg[0];
            if (args != null)
                ourArgs = (from t in args
                           select new KnownTypeInfo.MechodArg()
                           {
                               Type = t.Item1,
                               CPPType = t.Item2
                           }).ToArray();

            var incfiles = includeFiles;
            if (incfiles == null)
            {
                incfiles = new string[0];
            }

            kt.Methods = new KnownTypeInfo.MethodInfo[] { new KnownTypeInfo.MethodInfo() { Name = methodName, CPPName = cppMethodName, Arguments = ourArgs, IncludeFiles = incfiles } };
            gSetTypes.Add(kt);
        }