Json自动生成C#代码的工具

需求

由于现在项目里面与服务器通信的数据使用的Json格式,在每次服务器添加协议的时候客户端都要根据服务器返回的数据对照写一遍解析的数据类和解析类,这样重复性的工作比较浪费时间,所以写了一个Json自动生成C#代码的工具,只要把服务器返回的Json数据用这个工具转换一下就可以自动生成对应的C#解析的代码。

例子

比如服务器添加了一条数据协议,内容是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
    "http_code": 200,
    "data": {
        "code_id": 164872,
        "book_id": 1,
        "free_goods": [
            {
                "price": 10.1,
                "order_id": "12333333",
            }
        ]
    },
    "elapsed": 26
}

经过转换工具自动生成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
using LitJson;

[System.Serializable]
public class Free_goods {

	public double  price{get; set;}
	public string  order_id{get; set;}

} 

[System.Serializable]
public class Data {

	public int code_id {get; set;}
	public int book_id {get; set;}
	public Free_goods[] free_goods{get; set;}

} 

[System.Serializable]
public class GoodsInfo {

	public int http_code {get; set;}
	public Data data{get; set;}
	public int elapsed {get; set;}

} 

public class GoodsInfoParser {

	public GoodsInfo Data {get; private set;}

	public GoodsInfoParser(string jsonStr) {
 		Parse(jsonStr);  
	}

	private void Parse(string jsonStr) {
		Data = JsonMapper.ToObject<GoodsInfo>(jsonStr);  
	}

 }

那么我们在使用的时候只需要使用GoodsInfoParser类即可得到我们需要的数据:

1
2
3
4
5
6
7

//jsonData就是上面例子中的json数据
GoodsInfoParser goodsInfo = new GoodsInfoParser(jsonData);

//这里访问price变量
Console.WriteLine(goodsInfo.Data.data.free_goods[0].price);

这样不用每次手动去写Free_goods,Data, GoodsInfo这些类了,自动生成也减少了出错的几率。

工具代码

解析的库使用的LitJson

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
 * Create by elang
 * 2017-02-11
 */

using System;
using System.IO;
using LitJson;

namespace Json2CSharp
{
	public class GenClassFromJson
	{
		private string outputFilePath;

		private const string propertyTypeDesc = "{get; set;}\n";

		public GenClassFromJson(string jsonStr, string className)
		{
			outputFilePath = "../../" + className + ".cs";

			if (File.Exists(outputFilePath))
			{
				File.Delete(outputFilePath);
			}

			AppendNameSpace("using LitJson;\n\n");

			ParseJson(jsonStr, className);

			AppendParseJsonClass(className);
		}

		private string GetValueType(JsonReader reader)
		{
			return reader.Value != null ? reader.Value.GetType().ToString() : "";
		}

		public void ParseJson(string jsonStr, string rootName)
		{
			JsonReader reader = new JsonReader(jsonStr);

			ParseJsonNode(reader, rootName);
		}

		public void ParseJsonNode(JsonReader reader, string rootName)
		{
			string classDesc = string.Empty;
			string prePropertyValue = string.Empty;

			do
			{
				//Console.WriteLine("{0,14} {1,10} {2,16}", reader.Token, reader.Value, GetValueType(reader));

				if (reader.Token == JsonToken.ObjectStart)
				{
					if (string.IsNullOrEmpty(classDesc))
					{
						classDesc = "\n[System.Serializable]\npublic class " + rootName + " {\n\n";
					}
					else
					{
						string objName = ToHumpFormat(prePropertyValue);

						classDesc += "\tpublic " + objName + " " + prePropertyValue + propertyTypeDesc;

						ParseJsonNode(reader, objName);
					}
				}
				else if (reader.Token == JsonToken.ObjectEnd)
				{
					classDesc += "\n} \n";

					AppendToLocalFile(classDesc);

					return;
				}
				else if (reader.Token == JsonToken.PropertyName)
				{
					prePropertyValue = reader.Value.ToString();
				}
				else if (reader.Token == JsonToken.ArrayStart)
				{
					reader.Read();

					if (reader.Token == JsonToken.ObjectStart)
					{
						string objName = ToHumpFormat(prePropertyValue);
						classDesc += "\tpublic " + objName + "[] " + prePropertyValue + propertyTypeDesc;

						ParseJsonNode(reader, objName);
					}
				}
				else if (reader.Token == JsonToken.ArrayEnd)
				{
					//nothing to do
				}
				else if (reader.Token == JsonToken.Int)
				{
					classDesc += "\tpublic int " + prePropertyValue + " {get; set;}\n";
				}
				else if (reader.Token == JsonToken.Long || 
				         reader.Token == JsonToken.Boolean || 
				         reader.Token == JsonToken.Double || 
				         reader.Token == JsonToken.String
				        )
				{
					string type = GetValueType(reader);

					string[] typeParts = type.Split('.');

					classDesc += "\tpublic " + typeParts[typeParts.Length - 1].ToLower() + "  " + prePropertyValue + propertyTypeDesc;
				}

			} while (reader.Read());

			Console.WriteLine("Json to csharp complete!");
		}

		private void AppendParseJsonClass(string className)
		{
			string parseClassDesc = "\n\npublic class " + className + "Parser {\n\n";

			parseClassDesc += "\tpublic " + className + " Data {get; private set;}\n\n";

			parseClassDesc += "\tpublic " + className + "Parser(string jsonStr) {\n \t\tParse(jsonStr);  \n\t}\n\n";

			parseClassDesc += "\tprivate void Parse(string jsonStr) {\n\t\tData = JsonMapper.ToObject<" + className + ">(jsonStr);  \n\t}\n";

			parseClassDesc += "\n }";

			AppendToLocalFile(parseClassDesc);
		}

		void AppendNameSpace(string namespaceStr)
		{
			AppendToLocalFile(namespaceStr);

			//TODO
		}

		private string ToHumpFormat(string value)
		{
			return value.Substring(0, 1).ToUpper() + value.Substring(1, value.Length - 1);
		}

		private void AppendToLocalFile(string classDesc)
		{
			File.AppendAllText(outputFilePath, classDesc);
		}
	}
}