지난글(Packet Generator [1])에 이어서 개발을 진행한다.
💻 코드
GenPacket 생성
패킷 자동화 스크립트를 파일로 만들기 위해 Main의 using안에 구현해준다.
1
2
3
4
5
6
7
8
static string genPackets;
class Program
{
using (XmlReader r = XmlReader.Create("PDL.xml", settings))
{
File.WriteAllText("GenPackets.cs", genPackets);
}
}
문자열 -> 코드.cs 포맷 작업
ParsePacket
안에서 검증이 끝나면 Tuple
을 통해 memberCode
, readCode
, writeCode
를 받도록 생성한다.
생성된 Tuple
은 string.Format
을 통해 문자열을 코드화시킬 PacketForamt
을 정하고
그 다음으로 PacketFormat
에 정해진 변수를 넣어준다. ( {0}, {1}, .. )
1
2
3
4
5
6
7
8
9
10
11
public static void ParsePacket(XmlReader r)
{
Tuple<string, string, string> t = ParseMembers(r);
// {0} 클래스 이름
// {1} 멤버 변수들
// {2} 멤버 변수 Read
// {3} 멤버 변수 Write
genPackets += string.Format(PacketFormat.packetFormat, packetName, t.Item1, t.Item2, t.Item3);
}
ParseMembers 메소드
ParseMemeber
메소드의 반환값을 Tuple
로 수정한다.
Tuple
안에 넣을 memberCode
, readCode
, writeCode
를 선언해준다.
while
안에서 띄어쓰기 체크 후 switch
안에서 각 포맷에 맞는 코드화를 진행한다.
코드화가 완료되면 가독성을 위해 정렬해준다.
코드에 주석 참고
[ Source Code (Click) ]
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
// {0} 멤버 변수들
// {1} 멤버 변수 Read
// {2} 멤버 변수 Write
public static Tuple<string, string, string> ParseMembers(XmlReader r)
{
string packetName = r["name"];
string memberCode = "";
string readCode = "";
string writeCode = "";
int depth = r.Depth + 1;
while (r.Read())
{
if (r.Depth != depth)
break;
// null 체크
string memberName = r["name"];
if (string.IsNullOrEmpty(memberName))
{
Console.WriteLine("Member without name");
return null;
}
// 띄어쓰기 용도
if (string.IsNullOrEmpty(memberCode) == false)
memberCode += Environment.NewLine;
if (string.IsNullOrEmpty(readCode) == false)
readCode += Environment.NewLine;
if (string.IsNullOrEmpty(writeCode) == false)
writeCode += Environment.NewLine;
// 변수 타입마다 알맞게 포맷
string memberType = r.Name.ToLower();
switch (memberType)
{
case "bool":
case "short":
case "ushort":
case "int":
case "long":
case "float":
case "double":
memberCode += string.Format(PacketFormat.memberFormat, memberType, memberName);
readCode += string.Format(PacketFormat.readFormat, memberName, ToMemberType(memberType), memberType);
writeCode += string.Format(PacketFormat.writeFormat, memberName, memberType);
break;
case "string":
memberCode += string.Format(PacketFormat.memberFormat, memberType, memberName);
readCode += string.Format(PacketFormat.readStringFormat, memberName);
writeCode += string.Format(PacketFormat.writeStringFormat, memberName);
break;
case "list":
Tuple<string, string, string> t = ParseList(r);
memberCode += t.Item1;
readCode += t.Item2;
writeCode += t.Item3;
break;
default:
break;
}
}
// 코드 정렬화 (띄어쓰기 후 탭)
memberCode = memberCode.Replace("\n", "\n\t");
readCode = readCode.Replace("\n", "\n\t\t");
writeCode = writeCode.Replace("\n", "\n\t\t");
return new Tuple<string, string, string>(memberCode, readCode, writeCode);
}
// 리스트 파싱
public static Tuple<string, string, string> ParseList(XmlReader r)
{
// null 체크
string listName = r["name"];
if (string.IsNullOrEmpty(listName))
{
Console.WriteLine("List without name");
return null;
}
// List안에서 똑같은 파싱이 이루어지기 때문에 ParseMemeber 재사용
Tuple<string, string, string> t = ParseMembers(r);
string memberCode = string.Format(PacketFormat.memberListFormat,
FirstCharToUpper(listName),
FirstCharToLower(listName),
t.Item1,
t.Item2,
t.Item3);
string readCode = string.Format(PacketFormat.readListFormat,
FirstCharToUpper(listName),
FirstCharToLower(listName));
string writeCode = string.Format(PacketFormat.writeListFormat,
FirstCharToUpper(listName),
FirstCharToLower(listName));
return new Tuple<string, string, string>(memberCode, readCode, writeCode);
}
// To... 변수 타입마다 쓰임이 다르므로 체크해주기
public static string ToMemberType(string memberType)
{
switch(memberType)
{
case "bool":
return "ToBoolean";
case "short":
return "ToInt16";
case "ushort":
return "ToUInt16";
case "int":
return "ToInt32";
case "long":
return "ToInt64";
case "float":
return "ToSingle";
case "double":
return "ToDouble";
default:
return "";
}
}
// 첫 글자 대문자 만들기
public static string FirstCharToUpper(string input)
{
if (string.IsNullOrEmpty(input))
return "";
return input[0].ToString().ToUpper() + input.Substring(1);
}
// 첫 글자 소문자 만들기
public static string FirstCharToLower(string input)
{
if (string.IsNullOrEmpty(input))
return "";
return input[0].ToString().ToLower() + input.Substring(1);
}