欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

利用反射生成接口列表

程序员文章站 2022-04-05 11:26:35
公司产品对外公布的接口, 评审后才能发布, 然后要求生成接口文档(去除注释, 这样更能检查接口命名是否合理). 之前用的是微软的一个免费工具, 但好久都没有更新了, 对新一点的C#语法不支持, 生成的文档是错误的, 如果不想手动从代码复制方法签名, 只能手写一个工具了 这个段代码以满足公司要求来编写 ......

      公司产品对外公布的接口, 评审后才能发布, 然后要求生成接口文档(去除注释, 这样更能检查接口命名是否合理).

      之前用的是微软的一个免费工具, 但好久都没有更新了, 对新一点的c#语法不支持, 生成的文档是错误的, 如果不想手动从代码复制方法签名, 只能手写一个工具了

      这个段代码以满足公司要求来编写, 没有多余精力去优化代码了, 其中用到了扩展方法导致很多地方不合理. 但是总归不用手动写文档了, 避免了很多无意义的工作.

 

  

    // first: install-package npoi
    using npoi.xwpf.usermodel;
    using system;
    using system.collections.generic;
    using system.io;
    using system.linq;
    using system.reflection;

    public static class interfaceexporthelper
    {
        static bindingflags bindingflags = bindingflags.public | bindingflags.nonpublic | bindingflags.instance | bindingflags.declaredonly | bindingflags.static;

        public static int spaceincreasecountofeachlevel = 4;
        public static string csharpclasscolor = "2b93af";
        public static string csharpkeywordcolor = "0000ff";
        public static bool isshowparameterdefaultvalue = false;

        public static void separateinterfacetodocument(string assemblypath, string outputdocpath)
        {
            var assembly = assembly.loadfrom(assemblypath);
            var types = assembly.gettypes().orderby(t => t.name);
            xwpfdocument doc = new xwpfdocument();
            var spacecount = 0;
            foreach (var type in types)
            {
                if (type.isclass)
                {
                    var p = dealclass(type, doc, spacecount);
                    if (p != null)
                    {
                        p.appendcarriagereturn();
                    }
                }
                else if (type.isenum)
                {
                    var p = dealenum(type, doc, spacecount);
                    if (p != null)
                    {
                        p.appendcarriagereturn();
                    }
                }
                else if (type.isvaluetype)
                {
                    var p = dealstruct(type, doc, spacecount);
                    if (p != null)
                    {
                        p.appendcarriagereturn();
                    }
                }
            }

            var fs = new filestream(outputdocpath, filemode.create);
            doc.write(fs);
            fs.close();
        }



        static xwpfparagraph dealclass(type type, xwpfdocument doc, int spacecount)
        {
            if (!type.ispublic)
            {
                return null;
            }
            //if (type.isnestedprivate)
            //{
            //    return null;
            //}
            if (type.name.startswith("<"))
            {
                return null;
            }
            var p = doc.createparagraph();
            p.appendspaces(spacecount);
            if (type.ispublic)
            {
                p.appendkeywordcsharp("public");
            }
            else
            {
                p.appendkeywordcsharp("internal");
            }
            p.appendspaces();

            if (type.isabstract && type.issealed)
            {
                p.appendkeywordcsharp("static");
                p.appendspaces();
            }
            else if (type.issealed)
            {
                p.appendkeywordcsharp("sealed");
                p.appendspaces();
            }
            else if (type.isabstract)
            {
                p.appendkeywordcsharp("abstract");
                p.appendspaces();
            }

            p.appendkeywordcsharp("class");
            p.appendspaces();
            p.appendclasscsharp(type.name);
            bool hasbasetype = false;
            if (type.basetype != null && type.basetype != typeof(object))
            {
                hasbasetype = true;
                p.appendtext(" : ");
                dispalytype(type.basetype, p);
            }
            bool isfisrtinterface = true;
            foreach (var interfacetype in type.getinterfaces())
            {
                if (!hasbasetype)
                {
                    p.appendtext(" : ");
                }
                if (!isfisrtinterface || hasbasetype)
                {
                    p.appendtext(", ");
                }
                dispalytype(interfacetype, p);
                isfisrtinterface = false;
            }
            p.appendcarriagereturn();

            var tempspacecount = spacecount;// - spaceincreasecountofeachlevel > 0 ? spacecount - spaceincreasecountofeachlevel : 0;
            p.appendspaces(tempspacecount);
            p.appendtext("{");
            p.appendcarriagereturn();



            bool hasaddedsomething = false;
            foreach (var filedinfo in type.getfields(bindingflags))
            {
                if (!filedinfo.ispublic && !filedinfo.isfamily)
                {
                    continue;
                }
                dealfieldinfo(filedinfo, p, spacecount + spaceincreasecountofeachlevel);
                hasaddedsomething = true;
            }
            if (hasaddedsomething) p.appendcarriagereturn();




            hasaddedsomething = false;
            foreach (constructorinfo constructorinfo in type.getconstructors(bindingflags.nonpublic | bindingflags.public | bindingflags.instance))
            {
                if (dealconstructor(constructorinfo, p, spacecount + spaceincreasecountofeachlevel) == true)
                {
                    hasaddedsomething = true;
                }
            }
            if (hasaddedsomething) p.appendcarriagereturn();



            hasaddedsomething = false;
            foreach (var propertyinfo in type.getproperties(bindingflags))
            {
                if (dealproperty(propertyinfo, p, spacecount + spaceincreasecountofeachlevel) == true)
                {
                    hasaddedsomething = true;
                }
            }
            if (hasaddedsomething) p.appendcarriagereturn();



            hasaddedsomething = false;
            foreach (methodinfo method in type.getmethods(bindingflags))
            {
                if (dealmethod(method, p, spacecount + spaceincreasecountofeachlevel) == true)
                {
                    hasaddedsomething = true;
                }
            }
            if (hasaddedsomething) p.appendcarriagereturn();
            p.removerun(p.runs.count - 1);
            p.appendspaces(tempspacecount);
            p.appendtext("}");
            return p;
        }

        static bool dealfieldinfo(fieldinfo fieldinfo, xwpfparagraph p, int spacecount)
        {
            if (!(fieldinfo.ispublic || fieldinfo.isfamily))
            {
                return false;
            }
            //if (fieldinfo.isprivate)
            //{
            //    return false;
            //}
            p.appendspaces(spacecount);
            var eventfieldlist = new list<fieldinfo>();

            if (fieldinfo.ispublic)
            {
                p.appendkeywordcsharp("public");
            }
            else if (fieldinfo.isfamily)
            {
                p.appendkeywordcsharp("protected");
            }
            else if (fieldinfo.isassembly)
            {
                p.appendkeywordcsharp("internal");
            }
            else if (fieldinfo.isfamilyorassembly)
            {
                p.appendkeywordcsharp("internal protected");
            }
            p.appendspaces();

            if (fieldinfo.isinitonly)
            {
                p.appendkeywordcsharp("readonly");
                p.appendspaces();
            }

            if (fieldinfo.isstatic)
            {
                p.appendkeywordcsharp("static");
                p.appendspaces();
            }

            dispalytype(fieldinfo.fieldtype, p);
            p.appendspaces();

            p.appendtext(fieldinfo.name);
            p.appendtext(";");
            p.appendcarriagereturn();
            return true;
        }

        static bool dealproperty(propertyinfo propertyinfo, xwpfparagraph p, int spacecount)
        {
            accessormodifier? getteraccessormodifier = null, setteraccessormodifier = null;
            if (propertyinfo.canread)
            {
                getteraccessormodifier = getaccessormodifier(propertyinfo.getmethod);
            }
            if (propertyinfo.canwrite)
            {
                setteraccessormodifier = getaccessormodifier(propertyinfo.setmethod);
            }

            var mainaccessormodifier = gethighaccessormodifier(getteraccessormodifier, setteraccessormodifier);

            if (!(mainaccessormodifier == accessormodifier.public || mainaccessormodifier == accessormodifier.protected))
            {
                return false;
            }

            p.appendspaces(spacecount);

            p.appendkeywordcsharp(accessormodifiertostring(mainaccessormodifier));
            p.appendspaces();

            dispalytype(propertyinfo.propertytype, p);
            p.appendspaces();

            p.appendtext(propertyinfo.name);
            p.appendspaces();

            p.appendtext("{");
            if (propertyinfo.canread && getteraccessormodifier >= accessormodifier.protected)
            {
                p.appendspaces();
                if (getteraccessormodifier != mainaccessormodifier)
                {
                    p.appendkeywordcsharp(accessormodifiertostring(getteraccessormodifier.value));
                    p.appendspaces();
                }
                p.appendkeywordcsharp("get;");
            }
            if (propertyinfo.canwrite && setteraccessormodifier >= accessormodifier.protected)
            {
                p.appendspaces();
                if (setteraccessormodifier != mainaccessormodifier)
                {
                    p.appendkeywordcsharp(accessormodifiertostring(setteraccessormodifier.value));
                    p.appendspaces();
                }
                p.appendkeywordcsharp("set;");
            }
            p.appendspaces();
            p.appendtext("}");
            p.appendcarriagereturn();
            return true;
        }

        static bool dealconstructor(constructorinfo constructorinfo, xwpfparagraph p, int spacecount)
        {
            if (!(constructorinfo.ispublic || constructorinfo.isfamily))
            {
                return false;
            }

            //if (constructorinfo.isprivate)
            //{
            //    return false;
            //}

            p.appendspaces(spacecount);
            if (constructorinfo.ispublic)
            {
                p.appendkeywordcsharp("public");
            }
            else if (constructorinfo.isfamily)
            {
                p.appendkeywordcsharp("protected");
            }
            else if (constructorinfo.isassembly)
            {
                p.appendkeywordcsharp("internal");
            }
            else if (constructorinfo.isfamilyorassembly)
            {
                p.appendkeywordcsharp("internal protected");
            }
            p.appendspaces();


            if (constructorinfo.isabstract)
            {
                p.appendkeywordcsharp("abstract");
                p.appendspaces();
            }

            p.appendclasscsharp(constructorinfo.declaringtype.name);
            p.appendtext("(");
            bool isfirst = true;
            foreach (var parameterinfo in constructorinfo.getparameters())
            {
                if (!isfirst)
                {
                    p.appendtext(", ");
                }
                dispalytype(parameterinfo.parametertype, p);
                p.appendspaces();
                p.appendtext(parameterinfo.name);
                isfirst = false;
            }
            p.appendtext(");");
            p.appendcarriagereturn();
            return true;
        }

        static bool dealmethod(methodinfo method, xwpfparagraph p, int spacecount)
        {
            if (!(method.ispublic || method.isfamily))
            {
                return false;
            }
            //if (method.isprivate)
            //{
            //    return false;
            //}

            if (method.name.startswith("get_") || method.name.startswith("set_"))
            {
                return false;
            }
            p.appendspaces(spacecount);
            if (method.name == "finalize")
            {
                p.appendtext("~");
                p.appendclasscsharp(method.declaringtype.name);
                p.appendtext("();");
                p.appendcarriagereturn();
                return true;
            }

            if (method.ispublic)
            {
                p.appendkeywordcsharp("public");
            }
            else if (method.isfamily)
            {
                p.appendkeywordcsharp("protected");
            }
            else if (method.isassembly)
            {
                p.appendkeywordcsharp("internal");
            }
            else if (method.isfamilyandassembly)
            {
                p.appendkeywordcsharp("internal protected");
            }
            p.appendspaces();

            if (method.isstatic)
            {
                p.appendkeywordcsharp("static");
                p.appendspaces();
            }
            // a. override parent class method, 
            // b.implement a interface
            // both have final & virtual keywords
            bool issealed = false;
            if (method.isfinal && method != method.getbasedefinition())
            {
                p.appendkeywordcsharp("sealed");
                p.appendspaces();
                issealed = true;
            }
            if (method.isvirtual)
            {
                if (method != method.getbasedefinition())
                {
                    p.appendkeywordcsharp("override");
                }
                else
                {
                    if (!method.isfinal)
                    {
                        p.appendkeywordcsharp("virtual");
                    }
                }
                p.appendspaces();
            }
            if (method.isabstract)
            {
                p.appendkeywordcsharp("abstract");
                p.appendspaces();
            }

            dispalytype(method.returntype, p);
            p.appendspaces();

            p.appendtext(method.name);
            p.appendtext("(");


            bool isfirst = true;
            foreach (var parameterinfo in method.getparameters())
            {
                if (!isfirst)
                {
                    p.appendtext(", ");
                }

                if (parameterinfo.isout)
                {
                    p.appendkeywordcsharp("out");
                    p.appendspaces();
                }
                else if (parameterinfo.isin)
                {
                    p.appendkeywordcsharp("in");
                    p.appendspaces();
                }
                else if (parameterinfo.parametertype.isbyref)
                {
                    p.appendkeywordcsharp("ref");
                    p.appendspaces();
                }

                dispalytype(parameterinfo.parametertype, p);
                p.appendspaces();
                p.appendtext(parameterinfo.name);
                if (isshowparameterdefaultvalue && parameterinfo.hasdefaultvalue)
                {
                    p.appendspaces();
                    p.appendtext("=");
                    p.appendspaces();
                    if (parameterinfo.defaultvalue == null)
                    {
                        p.appendtext("null");
                    }
                    else if (parameterinfo.parametertype == typeof(string))
                    {
                        p.appendtext("\"");
                        p.appendtext(parameterinfo.defaultvalue.tostring());
                        p.appendtext("\"");
                    }
                    else if (parameterinfo.parametertype == typeof(char))
                    {
                        p.appendtext("'");
                        p.appendtext(parameterinfo.defaultvalue.tostring());
                        p.appendtext("'");
                    }
                    else if (parameterinfo.parametertype.isenum)
                    {
                        dispalytype(parameterinfo.parametertype, p);
                        p.appendtext(".");
                        p.appendtext(parameterinfo.defaultvalue.tostring());
                    }
                    else
                    {
                        p.appendtext(parameterinfo.defaultvalue.tostring());
                    }
                }
                isfirst = false;
            }

            p.appendtext(");");
            p.appendcarriagereturn();
            return true;
        }

        static void dispalytype(type type, xwpfparagraph p)
        {
            // nullable<> need change to like int?
            if (type.isgenerictype && type.getgenerictypedefinition() == typeof(nullable<>))
            {
                dispalytype(type.getgenericarguments()[0], p);
                p.appendtext("?");
                return;
            }

            var typename = type.name;
            if (typename.contains("`"))
            {
                typename = typename.substring(0, typename.lastindexof('`'));
            }
            typename = changetonormalname(typename);
            p.appendclasscsharp(typename);
            if (type.isgenerictype)
            {
                p.appendtext("<");
                bool isfisrt = true;
                foreach (var genericargumenttype in type.getgenericarguments())
                {
                    if (!isfisrt)
                    {
                        p.appendtext(", ");
                    }
                    dispalytype(genericargumenttype, p);
                    isfisrt = false;
                }
                p.appendtext(">");
            }
        }

        static string changetonormalname(string typename)
        {
            typename = typename.trimend('&');
            switch (typename)
            {
                case "void": return "void";
                case "object": return "object";
                case "string": return "string";
                case "boolean": return "bool";
                case "byte": return "byte";
                case "char": return "char";
                case "int16": return "short";
                case "int32": return "int";
                case "int64": return "long";
                case "single": return "float";
                case "double": return "double";
                default:
                    return typename;
            }
        }

        static xwpfparagraph dealenum(type type, xwpfdocument doc, int spacecount)
        {
            if (type.isnestedprivate)
            {
                return null;
            }
            var p = doc.createparagraph();
            if (type.getcustomattribute<flagsattribute>() != null)
            {
                p.appendspaces(spacecount);
                p.appendtext("[");
                p.appendkeywordcsharp("flags");
                p.appendtext("]");
                p.appendcarriagereturn();
            }
            p.appendspaces(spacecount);
            if (type.ispublic)
            {
                p.appendkeywordcsharp("public");
            }
            else if (type.isnestedassembly)
            {
                p.appendkeywordcsharp("internal");
            }
            p.appendspaces();

            p.appendkeywordcsharp("enum");
            p.appendspaces();
            p.appendclasscsharp(type.name);

            var tempspacecount = spacecount;// - spaceincreasecountofeachlevel > 0 ? spacecount - spaceincreasecountofeachlevel : 0;
            p.appendcarriagereturn();
            p.appendspaces(tempspacecount);
            p.appendtext("{");
            p.appendcarriagereturn();

            foreach (var enumname in type.getenumnames())
            {
                p.appendspaces(spacecount + spaceincreasecountofeachlevel);
                p.appendtext(enumname);
                p.appendtext(",");
                p.appendcarriagereturn();
            }
            p.appendspaces(tempspacecount);
            p.appendtext("}");
            return p;
        }

        static xwpfparagraph dealstruct(type type, xwpfdocument doc, int spacecount)
        {
            if (!type.ispublic)
            {
                return null;
            }
            //if (type.isnestedprivate)
            //{
            //    return null;
            //}
            if (type.name.startswith("<"))
            {
                return null;
            }
            var p = doc.createparagraph();
            p.appendspaces(spacecount);
            if (type.ispublic)
            {
                p.appendkeywordcsharp("public");
            }
            else
            {
                p.appendkeywordcsharp("internal");
            }
            p.appendspaces();


            p.appendkeywordcsharp("struct");
            p.appendspaces();
            p.appendclasscsharp(type.name);

            bool isfisrtinterface = true;
            foreach (var interfacetype in type.getinterfaces())
            {
                if (isfisrtinterface)
                {
                    p.appendtext(" : ");
                }
                else
                {
                    p.appendtext(", ");
                }
                dispalytype(interfacetype, p);
                isfisrtinterface = false;
            }
            p.appendcarriagereturn();

            var tempspacecount = spacecount;// - spaceincreasecountofeachlevel > 0 ? spacecount - spaceincreasecountofeachlevel : 0;
            p.appendspaces(tempspacecount);
            p.appendtext("{");
            p.appendcarriagereturn();



            bool hasaddedsomething = false;
            foreach (var filedinfo in type.getfields(bindingflags))
            {
                if (!filedinfo.ispublic && !filedinfo.isfamily)
                {
                    continue;
                }
                dealfieldinfo(filedinfo, p, spacecount + spaceincreasecountofeachlevel);
                hasaddedsomething = true;
            }
            if (hasaddedsomething) p.appendcarriagereturn();




            hasaddedsomething = false;
            foreach (constructorinfo constructorinfo in type.getconstructors(bindingflags.nonpublic | bindingflags.public | bindingflags.instance))
            {
                if (dealconstructor(constructorinfo, p, spacecount + spaceincreasecountofeachlevel) == true)
                {
                    hasaddedsomething = true;
                }
            }
            if (hasaddedsomething) p.appendcarriagereturn();



            hasaddedsomething = false;
            foreach (var propertyinfo in type.getproperties(bindingflags))
            {
                if (dealproperty(propertyinfo, p, spacecount + spaceincreasecountofeachlevel) == true)
                {
                    hasaddedsomething = true;
                }
            }
            if (hasaddedsomething) p.appendcarriagereturn();



            hasaddedsomething = false;
            foreach (methodinfo method in type.getmethods(bindingflags))
            {
                if (dealmethod(method, p, spacecount + spaceincreasecountofeachlevel) == true)
                {
                    hasaddedsomething = true;
                }
            }
            if (hasaddedsomething) p.appendcarriagereturn();
            p.removerun(p.runs.count - 1);
            p.appendspaces(tempspacecount);
            p.appendtext("}");
            return p;
        }

        static accessormodifier getaccessormodifier(methodinfo method)
        {
            if (method.ispublic)
            {
                return accessormodifier.public;
            }
            if (method.isassembly)
            {
                return accessormodifier.internal;
            }
            if (method.isfamily)
            {
                return accessormodifier.protected;
            }
            if (method.isfamilyorassembly)
            {
                return accessormodifier.internalprotected;
            }

            return accessormodifier.private;
        }

        static accessormodifier gethighaccessormodifier(accessormodifier? a, accessormodifier? b)
        {
            // a or b at least have one value
            if (a.hasvalue && b.hasvalue)
            {
                return (accessormodifier)math.max((int)a.value, (int)b.value);
            }
            else if (a.hasvalue == false)
            {
                return b.value;
            }
            else
            {
                return a.value;
            }
        }

        static string accessormodifiertostring(accessormodifier accessormodifier)
        {
            switch (accessormodifier)
            {
                case accessormodifier.public:
                    return "public";
                case accessormodifier.internal:
                    return "internal";
                case accessormodifier.protected:
                    return "protected";
                    break;
                case accessormodifier.internalprotected:
                    return "internal protected";
                case accessormodifier.private:
                    return "private";
                default:
                    return "";
            }
        }

        private enum accessormodifier
        {
            public = 100,
            protected = 95,
            internal = 90,
            internalprotected = 80,
            private = 70,
        }
    }

    internal static class nopiextension
    {
        internal static xwpfrun appendtext(this xwpfparagraph paragraph, string text, string color = "000000")
        {
            xwpfrun run = paragraph.createrun();
            run.settext(text);
            run.setcolor(color);
            return run;
        }

        internal static xwpfrun appendspaces(this xwpfparagraph paragraph, int spacecount = 1)
        {
            return paragraph.appendtext(new string(' ', spacecount));
        }

        internal static xwpfrun appendkeywordcsharp(this xwpfparagraph paragraph, string text)
        {
            return paragraph.appendtext(text, interfaceexporthelper.csharpkeywordcolor);
        }

        internal static xwpfrun appendclasscsharp(this xwpfparagraph paragraph, string text)
        {
            return paragraph.appendtext(text, interfaceexporthelper.csharpclasscolor);
        }

        internal static xwpfrun appendcarriagereturn(this xwpfparagraph paragraph)
        {
            var run = paragraph.createrun();
            run.addcarriagereturn();
            return run;
        }
    }

 

      用法

var assemblypath = @"d:\client\bin\debug\client.dll";
var outputdocpath = @"d:\client.docx";

interfaceexporthelper.isshowparameterdefaultvalue = false;
interfaceexporthelper.separateinterfacetodocument(assemblypath, outputdocpath);