/// <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 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 == "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
                {
                    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, WeixinTimestampHelper.FromBeijingTime((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;

                    default:
                        root.Add(new XElement(propName, prop.GetValue(entity, null)));
                        break;
                    }
                }
            }
            return(doc);
        }