最近很喜欢使用XML(C#的Linq to XML)。写个类后总想把它能用XML文件保存起来,一般我都是写个ToXElement函数然后在里面……
今天写烦了,想写一个通用的工具类,以便很方便地把一个类保存化为XML。
看看写出来的结果:
1 /************************************************************************\
2 * 把一个对象格式化为XML(元素),即:
3 * 1、该XML元素的名字为该对象的类型
4 * 2、对该对象中每一个公共属性(Property)转换为字符串(String)
5 * 保存到XML元素的属性中
6 * 把一个XML粘贴到一个对象中,即为上一过程的逆过程。
7 *
8 * 对象信息保存到XML中(然后再保存到文件)很显然将具有很高的可读性
9 \************************************************************************/
10 using System;
11 using System.Collections.Generic;
12 using System.Linq;
13 using System.Text;
14 using System.Xml.Linq;
15 namespace DotNetEx.FormatAsXml
16 {
17 /// <summary>
18 /// 标识能格式化为XML,可以被用在类和结构上,不可以继承,不支持多重标记
19 /// </summary>
20 [AttributeUsage(AttributeTargets.Class|AttributeTargets.Struct, Inherited = false,
21 AllowMultiple = false)]
22 public sealed class CanFormatToXmlAttribute : Attribute
23 {
24 public CanFormatToXmlAttribute () { }
25 }
26 /// <summary>
27 /// 标识该属性不用被格式化
28 /// </summary>
29 [AttributeUsage(AttributeTargets.Property,Inherited=false,
30 AllowMultiple=false)]
31 public sealed class DonotFormatToXmlAttribute:Attribute
32 {
33 public DonotFormatToXmlAttribute(){}
34 }
35 /// <summary>
36 /// 格式化为XML的格式器
37 /// </summary>
38 public static class XmlFormater
39 {
40 /// <summary>
41 /// 把一个对象格式化为XML,这个对象必须有CanFormatToXml属性(Attribute)
42 /// </summary>
43 /// <param name="o">要格式的对象</param>
44 /// <returns>格式化的XML元素</returns>
45 /// <exception type="UnsurportedTypeException">输入的对象的类型必须是支持格式化为XML的类型(有CanFormatToXml属性)</exception>
46 /// <exception type="ArgumentNullException">输入的对象不能为NULL</exception>
47 public static XElement ToXElement(object o){
48 if(o==null){
49 throw new ArgumentNullException("o");
50 }
51 Type t=o.GetType();
52 var atts= t.GetCustomAttributes(typeof(CanFormatToXmlAttribute),false);
53
54 if(atts.Length==0){
55 throw new UnsurportedTypeException(t);
56 }
57 XElement xml=new XElement(t.Name);
58 var propertyInfos=t.GetProperties();
59 foreach (var proi in propertyInfos) {
60 if(proi.CanRead){
61 if(proi.GetCustomAttributes(typeof(DonotFormatToXmlAttribute),false)
62 .Length==0){
63 var pg = proi.GetGetMethod();
64 object ret = pg.Invoke(o, null);
65 xml.Add(new XAttribute(proi.Name, Convert.ChangeType(ret, typeof(string))));
66 }
67 }
68 }
69 return xml;
70 }
71 /// <summary>
72 /// 从一个格式化好的XML中粘贴相关格式化信息到对象
73 /// </summary>
74 /// <param name="xml">输入的格式化好的XML</param>
75 /// <param name="obj">一个目标对象,其必须支持格式化为XML(有CanFormatToXml属性)</param>
76 public static void Pase(XElement xml, object obj){
77 if (xml == null) {
78 throw new ArgumentNullException("xml");
79 }
80
81 if(obj==null){
82 throw new ArgumentNullException("obj");
83 }
84
85 Type type = obj.GetType();
86 if (( type.GetCustomAttributes(typeof(CanFormatToXmlAttribute), false)
87 .Length == 0 ) ||
88 xml.Name!=type.Name
89 ) {
90 throw new UnsurportedTypeException(type);
91 }
92
93 var pis = type.GetProperties();
94 foreach (var pi in pis) {
95 if(pi.CanWrite){
96 if(pi.GetCustomAttributes(typeof(DonotFormatToXmlAttribute),false)
97 .Length==0){
98 var psm = pi.GetSetMethod(true);
99 psm.Invoke(obj,
100 new object[]{ Convert.ChangeType(
101 xml.Attribute(pi.Name).Value,
102 pi.PropertyType)}
103 );
104 }
105 }
106 }
107 }
108 /// <summary>
109 /// 不是支持格式化为XML(有CanFormatToXml属性)的类型
110 /// </summary>
111 public sealed class UnsurportedTypeException:Exception
112 {
113 public UnsurportedTypeException(Type t){
114 Type=t;
115 }
116 public Type Type{
117 private set;
118 get;
119 }
120 public override string Message
121 {
122 get
123 {
124 return "类型\""+Type+"\"不支持格式化为XML";
125 }
126 }
127 }
128 }
129 //*
130 static class Test
131 {
132 [CanFormatToXml()]
133 class Person{
134 public Person(String name ){
135 Name = name;
136 }
137 public string Name{
138 get;
139 private set;
140 }
141 public int Age{
142 get;
143 set;
144 }
145 public DateTime BirthDay {
146 get;
147 set;
148 }
149 [DonotFormatToXml()]
150 public Person Test{
151 get;
152 set;
153 }
154 }
155 static void Main(){
156 Person p=new Person("Hack"){
157 BirthDay=new DateTime(1990,1,1),
158 Age=19,
159 Test=new Person("Test"){
160 Age=20
161 }
162 };
163 var x=XmlFormater.ToXElement(p);
164 Console.WriteLine(x.ToString());
165 x.Attribute("Name").Value = "Changed";
166 XmlFormater.Pase(x, p);
167 Console.WriteLine(XmlFormater.ToXElement(p).ToString());
168 }
169 }
170 //*/
171 }
172
173
2 * 把一个对象格式化为XML(元素),即:
3 * 1、该XML元素的名字为该对象的类型
4 * 2、对该对象中每一个公共属性(Property)转换为字符串(String)
5 * 保存到XML元素的属性中
6 * 把一个XML粘贴到一个对象中,即为上一过程的逆过程。
7 *
8 * 对象信息保存到XML中(然后再保存到文件)很显然将具有很高的可读性
9 \************************************************************************/
10 using System;
11 using System.Collections.Generic;
12 using System.Linq;
13 using System.Text;
14 using System.Xml.Linq;
15 namespace DotNetEx.FormatAsXml
16 {
17 /// <summary>
18 /// 标识能格式化为XML,可以被用在类和结构上,不可以继承,不支持多重标记
19 /// </summary>
20 [AttributeUsage(AttributeTargets.Class|AttributeTargets.Struct, Inherited = false,
21 AllowMultiple = false)]
22 public sealed class CanFormatToXmlAttribute : Attribute
23 {
24 public CanFormatToXmlAttribute () { }
25 }
26 /// <summary>
27 /// 标识该属性不用被格式化
28 /// </summary>
29 [AttributeUsage(AttributeTargets.Property,Inherited=false,
30 AllowMultiple=false)]
31 public sealed class DonotFormatToXmlAttribute:Attribute
32 {
33 public DonotFormatToXmlAttribute(){}
34 }
35 /// <summary>
36 /// 格式化为XML的格式器
37 /// </summary>
38 public static class XmlFormater
39 {
40 /// <summary>
41 /// 把一个对象格式化为XML,这个对象必须有CanFormatToXml属性(Attribute)
42 /// </summary>
43 /// <param name="o">要格式的对象</param>
44 /// <returns>格式化的XML元素</returns>
45 /// <exception type="UnsurportedTypeException">输入的对象的类型必须是支持格式化为XML的类型(有CanFormatToXml属性)</exception>
46 /// <exception type="ArgumentNullException">输入的对象不能为NULL</exception>
47 public static XElement ToXElement(object o){
48 if(o==null){
49 throw new ArgumentNullException("o");
50 }
51 Type t=o.GetType();
52 var atts= t.GetCustomAttributes(typeof(CanFormatToXmlAttribute),false);
53
54 if(atts.Length==0){
55 throw new UnsurportedTypeException(t);
56 }
57 XElement xml=new XElement(t.Name);
58 var propertyInfos=t.GetProperties();
59 foreach (var proi in propertyInfos) {
60 if(proi.CanRead){
61 if(proi.GetCustomAttributes(typeof(DonotFormatToXmlAttribute),false)
62 .Length==0){
63 var pg = proi.GetGetMethod();
64 object ret = pg.Invoke(o, null);
65 xml.Add(new XAttribute(proi.Name, Convert.ChangeType(ret, typeof(string))));
66 }
67 }
68 }
69 return xml;
70 }
71 /// <summary>
72 /// 从一个格式化好的XML中粘贴相关格式化信息到对象
73 /// </summary>
74 /// <param name="xml">输入的格式化好的XML</param>
75 /// <param name="obj">一个目标对象,其必须支持格式化为XML(有CanFormatToXml属性)</param>
76 public static void Pase(XElement xml, object obj){
77 if (xml == null) {
78 throw new ArgumentNullException("xml");
79 }
80
81 if(obj==null){
82 throw new ArgumentNullException("obj");
83 }
84
85 Type type = obj.GetType();
86 if (( type.GetCustomAttributes(typeof(CanFormatToXmlAttribute), false)
87 .Length == 0 ) ||
88 xml.Name!=type.Name
89 ) {
90 throw new UnsurportedTypeException(type);
91 }
92
93 var pis = type.GetProperties();
94 foreach (var pi in pis) {
95 if(pi.CanWrite){
96 if(pi.GetCustomAttributes(typeof(DonotFormatToXmlAttribute),false)
97 .Length==0){
98 var psm = pi.GetSetMethod(true);
99 psm.Invoke(obj,
100 new object[]{ Convert.ChangeType(
101 xml.Attribute(pi.Name).Value,
102 pi.PropertyType)}
103 );
104 }
105 }
106 }
107 }
108 /// <summary>
109 /// 不是支持格式化为XML(有CanFormatToXml属性)的类型
110 /// </summary>
111 public sealed class UnsurportedTypeException:Exception
112 {
113 public UnsurportedTypeException(Type t){
114 Type=t;
115 }
116 public Type Type{
117 private set;
118 get;
119 }
120 public override string Message
121 {
122 get
123 {
124 return "类型\""+Type+"\"不支持格式化为XML";
125 }
126 }
127 }
128 }
129 //*
130 static class Test
131 {
132 [CanFormatToXml()]
133 class Person{
134 public Person(String name ){
135 Name = name;
136 }
137 public string Name{
138 get;
139 private set;
140 }
141 public int Age{
142 get;
143 set;
144 }
145 public DateTime BirthDay {
146 get;
147 set;
148 }
149 [DonotFormatToXml()]
150 public Person Test{
151 get;
152 set;
153 }
154 }
155 static void Main(){
156 Person p=new Person("Hack"){
157 BirthDay=new DateTime(1990,1,1),
158 Age=19,
159 Test=new Person("Test"){
160 Age=20
161 }
162 };
163 var x=XmlFormater.ToXElement(p);
164 Console.WriteLine(x.ToString());
165 x.Attribute("Name").Value = "Changed";
166 XmlFormater.Pase(x, p);
167 Console.WriteLine(XmlFormater.ToXElement(p).ToString());
168 }
169 }
170 //*/
171 }
172
173
那个静态类Test是用于测试的,测试结果:
<Person Name="Hack" Age="19" BirthDay="1990/1/1 0:00:00" />
<Person Name="Changed" Age="19" BirthDay="1990/1/1 0:00:00" />
还不错,能把一个对象的公有属性都写到XML元素中,反过来也能粘贴回对象。
原理分析:(代码很短很清晰,这里就不多说了)
从对象格式化到XML时,使用反射从Type得到属性信息,再得到属性的Getter,然后调用就行了;反过来也差不多。
注意那个Person.Name属性,它的Setter是私有的,不过粘贴时也能正常工作。