/// <summary>
        /// 将实体转为XML
        /// </summary>
        /// <typeparam name="T">RequestMessage或ResponseMessage</typeparam>
        /// <param name="entity">实体</param>
        /// <returns></returns>
        public static XDocument ConvertEntityToXml <T>(this T entity) where T : class, new()
        {
            entity = entity ?? new T();
            var doc = new XDocument();

            doc.Add(new XElement("xml"));
            var root = doc.Root;

            /* 注意!
             * 经过测试,微信对字段排序有严格要求,这里对排序进行强制约束
             */
            var propNameOrder = new List <string>()
            {
                "ToUserName", "FromUserName", "CreateTime", "MsgType"
            };

            //不同返回类型需要对应不同特殊格式的排序
            if (entity is ResponseMessageNews)
            {
                propNameOrder.AddRange(new[] { "ArticleCount", "Articles", "FuncFlag", /*以下是Atricle属性*/ "Title ", "Description ", "PicUrl", "Url" });
            }
            else if (entity is ResponseMessageTransfer_Customer_Service)
            {
                propNameOrder.AddRange(new[] { "TransInfo", "KfAccount", "FuncFlag" });
            }
            else if (entity is ResponseMessageMusic)
            {
                propNameOrder.AddRange(new[] { "Music", "FuncFlag", "ThumbMediaId", /*以下是Music属性*/ "Title ", "Description ", "MusicUrl", "HQMusicUrl" });
            }
            else if (entity is ResponseMessageImage)
            {
                propNameOrder.AddRange(new[] { "Image", /*以下是Image属性*/ "MediaId " });
            }
            else if (entity is ResponseMessageVoice)
            {
                propNameOrder.AddRange(new[] { "Voice", /*以下是Voice属性*/ "MediaId " });
            }
            else if (entity is ResponseMessageVideo)
            {
                propNameOrder.AddRange(new[] { "Video", /*以下是Video属性*/ "MediaId ", "Title", "Description" });
            }
            else
            {
                //如Text类型
                propNameOrder.AddRange(new[] { "Content", "FuncFlag" });
            }

            Func <string, int> orderByPropName = propNameOrder.IndexOf;

            var props = entity.GetType().GetProperties().OrderBy(p => orderByPropName(p.Name)).ToList();

            foreach (var prop in props)
            {
                var propName = prop.Name;
                if (propName == "Articles")
                {
                    //文章列表
                    var atriclesElement = new XElement("Articles");
                    var articales       = prop.GetValue(entity, null) as List <Article>;
                    foreach (var articale in articales)
                    {
                        var subNodes = ConvertEntityToXml(articale).Root.Elements();
                        atriclesElement.Add(new XElement("item", subNodes));
                    }
                    root.Add(atriclesElement);
                }
                else if (propName == "TransInfo")
                {
                    var transInfoElement = new XElement("TransInfo");
                    var transInfo        = prop.GetValue(entity, null) as List <CustomerServiceAccount>;
                    foreach (var account in transInfo)
                    {
                        var trans = ConvertEntityToXml(account).Root.Elements();
                        transInfoElement.Add(trans);
                    }

                    root.Add(transInfoElement);
                }
                else if (propName == "Music" || propName == "Image" || propName == "Video" || propName == "Voice")
                {
                    //音乐、图片、视频、语音格式
                    var musicElement = new XElement(propName);
                    var media        = prop.GetValue(entity, null);// as Music;
                    var subNodes     = ConvertEntityToXml(media).Root.Elements();
                    musicElement.Add(subNodes);
                    root.Add(musicElement);
                }
                else if (propName == "PicList")
                {
                    var picListElement = new XElement("PicList");
                    var picItems       = prop.GetValue(entity, null) as List <PicItem>;
                    foreach (var picItem in picItems)
                    {
                        var item = ConvertEntityToXml(picItem).Root.Elements();
                        picListElement.Add(item);
                    }
                    root.Add(picListElement);
                }
                //else if (propName == "KfAccount")
                //{
                //    //TODO:可以交给string处理
                //    root.Add(new XElement(propName, prop.GetValue(entity, null).ToString().ToLower()));
                //}
                else
                {
                    //其他非特殊类型
                    switch (prop.PropertyType.Name)
                    {
                    case "String":
                        root.Add(new XElement(propName,
                                              new XCData(prop.GetValue(entity, null) as string ?? "")));
                        break;

                    case "DateTime":
                        root.Add(new XElement(propName,
                                              DateTimeHelper.GetWeixinDateTime(
                                                  (DateTime)prop.GetValue(entity, null))));
                        break;

                    case "Boolean":
                        if (propName == "FuncFlag")
                        {
                            root.Add(new XElement(propName, (bool)prop.GetValue(entity, null) ? "1" : "0"));
                        }
                        else
                        {
                            goto default;
                        }
                        break;

                    case "ResponseMsgType":
                        root.Add(new XElement(propName, new XCData(prop.GetValue(entity, null).ToString().ToLower())));
                        break;

                    case "Article":
                        root.Add(new XElement(propName, prop.GetValue(entity, null).ToString().ToLower()));
                        break;

                    case "TransInfo":
                        root.Add(new XElement(propName, prop.GetValue(entity, null).ToString().ToLower()));
                        break;

                    default:
                        if (prop.PropertyType.IsClass && prop.PropertyType.IsPublic)
                        {
                            //自动处理其他实体属性
                            var subEntity = prop.GetValue(entity, null);
                            var subNodes  = ConvertEntityToXml(subEntity).Root.Elements();
                            root.Add(new XElement(propName, subNodes));
                        }
                        else
                        {
                            root.Add(new XElement(propName, prop.GetValue(entity, null)));
                        }
                        break;
                    }
                }
            }
            return(doc);
        }