惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

MyScale Blog
MyScale Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
阮一峰的网络日志
阮一峰的网络日志
罗磊的独立博客
博客园 - 叶小钗
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
美团技术团队
酷 壳 – CoolShell
酷 壳 – CoolShell
雷峰网
雷峰网
宝玉的分享
宝玉的分享
大猫的无限游戏
大猫的无限游戏
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Last Week in AI
Last Week in AI
爱范儿
爱范儿
小众软件
小众软件
K
Kaspersky official blog
P
Proofpoint News Feed
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - Franky
V
Vulnerabilities – Threatpost
博客园_首页
Microsoft Security Blog
Microsoft Security Blog
C
Cybersecurity and Infrastructure Security Agency CISA
V
V2EX
C
Check Point Blog
S
Schneier on Security
P
Palo Alto Networks Blog
IT之家
IT之家
GbyAI
GbyAI
T
Threat Research - Cisco Blogs
Hugging Face - Blog
Hugging Face - Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Apple Machine Learning Research
Apple Machine Learning Research
C
Cyber Attacks, Cyber Crime and Cyber Security
T
Tailwind CSS Blog
Project Zero
Project Zero
Y
Y Combinator Blog
V
Visual Studio Blog
Simon Willison's Weblog
Simon Willison's Weblog
T
Threatpost
Scott Helme
Scott Helme
L
LINUX DO - 热门话题
S
Securelist
C
CERT Recently Published Vulnerability Notes
A
Arctic Wolf
M
MIT News - Artificial intelligence
人人都是产品经理
人人都是产品经理

博客园 - 刘寅

一起来用Websocket(二):Websocket协议详细分析 一起来用Websocket-目录 一起来用Websocket(一)开篇 Websocket!Socket在HTML5复活 封闭式开发小记(11):封闭式开发的测试发布(制定版本规则,展现开发进度) 封闭式开发小记(10):封闭式开发的项目汇报(区分汇报类别和听众、争取最大认可) 封闭式开发小记(9):封闭式开发的最后一天(开发中的一些心情记录,和开发无关) 封闭式开发小记(8):封闭式开发的项目讨论 封闭式开发小记(7):如何和谐沟通、提高士气(结合开发实际冲突来深入讨论合作与沟通) 封闭式开发小记(6):封闭式开发的文档管理 封闭式开发小记(5):封闭式开发的敏捷开发 封闭式开发小记(4):封闭式开发的架构设计 封闭式开发小记(3):封闭式开发的人员配备 封闭式开发小记(1):封闭式开发的基本装备 封闭式开发小记(2):封闭式开发的时间安排 进程机制与并发程序设计-Linux下C实现-源码-makefile 进程机制与并发程序设计-Linux下C实现(二) 生产者与消费者问题 进程机制与并发程序设计-Linux下C实现(一) 睡觉的理发师问题 操作系统常用页面置换算法模拟实验下载 07 zsb C练习上机(二)
.NET 的 代码整洁之道 与 测试驱动开发 系列之(一)CleanCode 第14章
刘寅 · 2010-03-16 · via 博客园 - 刘寅

这两天看了和测试驱动相关的开发,一开始觉得有够恶心的,本来几行代码能搞定的事,却要这么折腾。给我的感觉是,一但测试代码相对稳定了,敏捷开发者就“敏捷”地打成重构,代码整洁的旗号去对那柔弱的旧代码大开杀戒了。顺理成章的去用一些模式,可以说TDD的那些测试,就成了免死金牌。

下面写出自己对TDD的几条理解吧;

1、先把测试代码写出来,想好怎么调用,虽然编译都没过

2、用最傻,弱智的方法把编译先过了

3、让测试代码的运行给过了,先解决代码“可用”,再考虑“整洁”问题

4、如果在修改代码的时候,如果出现了两个维度上的变化,则把测试回退,一次只处理一条变化(如果你够牛XX,可以多线程操作也行啊)

    注意自己的节奏。

5、看到重复代码要就提成接口或类,如果有默认实现,就提成类。

6、让代码替你思考,你把测试写到那里了,死角都在那了,你不用把逻辑放到脑子里面了,直接用测试验证就行了。

7、把一些未完成的功能,或者看得到的缺陷全都写到一个列表上,每次重构,都要解决对应的问题

8、如果重构和测试代码有冲突了,修改测试满足现有的重构

下面是自己重构的一个实践,希望 大家多多指教哈。。。

来源于<clean code >中的14章

第一部分,初稿

代码

  1 /*
  2  
  3  第14章,初稿
  4  重构步骤
  5  * 1.提取异常类ArgsException,并修改测试代码ArgsTest,支持新的异常类
  6  * 2.重构Args
  7  * 3.跑ArgsTest
  8  */
  9 using System;
 10 using System.Collections.Generic;
 11 using System.Text;
 12 using System.Collections;
 13 using System.Security.Policy;
 14 
 15 namespace CleanCode.Library
 16 {
 17 
 18     public class Args
 19     {
 20         private String schema;
 21         private String[] args;
 22         private bool valid = true;
 23         private IList<char> unexpectedArguments = new List<char>();
 24         private Dictionary<charbool> booleanArgs =
 25                                       new Dictionary<charbool>();
 26         private Dictionary<char, String> stringArgs = new Dictionary<char, String>();
 27         private Dictionary<char, System.Int32> intArgs = new Dictionary<charint>();
 28         private IList<char> argsFound = new List<char>();
 29         private int currentArgument;
 30         private char errorArgumentId = '\0';
 31         private String errorParameter = "TILT";
 32         private ErrorCode errorCode = ErrorCode.OK;
 33 
 34         private enum ErrorCode
 35         {
 36             OK, MISSING_STRING, MISSING_INTEGER, INVALID_INTEGER, UNEXPECTED_ARGUMENT
 37         }
 38 
 39         public Args(String schema, String[] args)
 40         {
 41             this.schema = schema;
 42             this.args = args;
 43             valid = parse();
 44         }
 45         private bool parse()
 46         {
 47             if (schema.Length == 0 && args.Length == 0)
 48                 return true;
 49             parseSchema();
 50             try
 51             {
 52                 parseArguments();
 53             }
 54             catch (ArgsException e)
 55             {
 56             }
 57             return valid;
 58         }
 59         private bool parseSchema()
 60         {
 61             string[] elementSet = schema.Split(new char[] { ',' });
 62             string element = string.Empty;
 63             for (int i = 0; i < elementSet.Length;i++ )
 64             {
 65                 element = elementSet[i];
 66                 if (element.Length > 0)
 67                 {
 68                     string trimmedElement = element.Trim();
 69                     parseSchemaElement(trimmedElement);
 70                 }
 71             }
 72             return true;
 73         }
 74         private void parseSchemaElement(string element)
 75         {
 76             char elementId = element[0];
 77             string elementTail = element.Substring(1);
 78             validateSchemaElementId(elementId);
 79             if (isBooleanSchemaElement(elementTail))
 80                 parseBooleanSchemaElement(elementId);
 81             else if (isStringSchemaElement(elementTail))
 82                 parseStringSchemaElement(elementId);
 83             else if (isIntegerSchemaElement(elementTail))
 84             {
 85                 parseIntegerSchemaElement(elementId);
 86             }
 87             else
 88             {
 89                 throw new FormatException(
 90                   string.Format("Argument: {0} has invalid format: {1}.",
 91                                 elementId, elementTail));
 92             }
 93         }
 94         private void validateSchemaElementId(char elementId)
 95         {
 96             if (!System.Char.IsLetter(elementId))
 97             {
 98                 throw new FormatException(
 99                   "Bad character:" + elementId + "in Args format: " + schema);
100             }
101         }
102         private void parseBooleanSchemaElement(char elementId)
103         {
104             booleanArgs.Add(elementId, false);
105         }
106         private void parseIntegerSchemaElement(char elementId)
107         {
108             intArgs.Add(elementId, 0);
109         }
110         private void parseStringSchemaElement(char elementId)
111         {
112             stringArgs.Add(elementId, "");
113         }
114         private bool isStringSchemaElement(String elementTail)
115         {
116             return elementTail.Equals("*");
117         }
118         private bool isBooleanSchemaElement(String elementTail)
119         {
120             return elementTail.Length == 0;
121         }
122         private bool isIntegerSchemaElement(String elementTail)
123         {
124             return elementTail.Equals("#");
125         }
126         private bool parseArguments()
127         {
128             for (currentArgument = 0; currentArgument < args.Length; currentArgument++)
129             {
130                 string arg = args[currentArgument];
131                 parseArgument(arg);
132             }
133             return true;
134         }
135         private void parseArgument(String arg)
136         {
137             if (arg.StartsWith("-"))
138                 parseElements(arg);
139         }
140         private void parseElements(String arg)
141         {
142             for (int i = 1; i < arg.Length; i++)
143                 parseElement(arg[i]);
144         }
145         private void parseElement(char argChar)
146         {
147             if (setArgument(argChar))
148                 argsFound.Add(argChar);
149             else
150             {
151                 unexpectedArguments.Add(argChar);
152                 errorCode = ErrorCode.UNEXPECTED_ARGUMENT;
153                 valid = false;
154             }
155         }
156         private bool setArgument(char argChar)
157         {
158             if (isBooleanArg(argChar))
159                 setBooleanArg(argChar, true);
160             else if (isStringArg(argChar))
161                 setStringArg(argChar);
162             else if (isIntArg(argChar))
163                 setIntArg(argChar);
164             else
165                 return false;
166             return true;
167         }
168         private bool isIntArg(char argChar) { return intArgs.ContainsKey(argChar); }
169         private void setIntArg(char argChar)
170         {
171             currentArgument++;
172             String parameter = null;
173             try
174             {
175                 parameter = args[currentArgument];
176                 intArgs[argChar] = int.Parse(parameter);
177                 
178             }
179             catch (IndexOutOfRangeException e)
180             {
181                 valid = false;
182                 errorArgumentId = argChar;
183                 errorCode = ErrorCode.MISSING_INTEGER;
184                 throw new ArgsException();
185             }
186             catch (FormatException e)
187             {
188                 valid = false;
189                 errorArgumentId = argChar;
190                 errorParameter = parameter;
191                 errorCode = ErrorCode.INVALID_INTEGER;
192                 throw new ArgsException();
193             }
194         }
195         private void setStringArg(char argChar)
196         {
197             currentArgument++;
198             try
199             {
200                
201                 stringArgs[argChar]= args[currentArgument];
202             }
203             catch (IndexOutOfRangeException e)
204             {
205                 valid = false;
206                 errorArgumentId = argChar;
207                 errorCode = ErrorCode.MISSING_STRING;
208                 throw new ArgsException();
209             }
210         }
211         private bool isStringArg(char argChar)
212         {
213             return stringArgs.ContainsKey(argChar);
214         }
215         private void setBooleanArg(char argChar, bool value)
216         {
217             booleanArgs[argChar] = value;
218         }
219         private bool isBooleanArg(char argChar)
220         {
221             return booleanArgs.ContainsKey(argChar);
222         }
223         public int cardinality()
224         {
225             return argsFound.Count;
226         }
227         public String usage()
228         {
229             if (schema.Length > 0)
230                 return "-[" + schema + "]";
231             else
232                 return "";
233         }
234         public String errorMessage()
235         {
236             switch (errorCode)
237             {
238                 case ErrorCode.OK:
239                     throw new Exception("TILT: Should not get here.");
240                 case ErrorCode.UNEXPECTED_ARGUMENT:
241                     return unexpectedArgumentMessage();
242                 case ErrorCode.MISSING_STRING:
243                     return String.Format("Could not find string parameter for -%c.",
244                                          errorArgumentId);
245                 case ErrorCode.INVALID_INTEGER:
246                     return String.Format("Argument -%c expects an integer but was '%s'.",
247                                          errorArgumentId, errorParameter);
248                 case ErrorCode.MISSING_INTEGER:
249                     return String.Format("Could not find integer parameter for -%c.",
250                                          errorArgumentId);
251             }
252             return "";
253         }
254         private String unexpectedArgumentMessage()
255         {
256             char c = '\0';
257             StringBuilder message = new StringBuilder("Argument(s) -");
258             for (int i = 0; i < unexpectedArguments.Count; i++)
259             {
260                 c = unexpectedArguments[i];
261                 message.Append(c);
262             }
263             message.Append(" unexpected.");
264             return message.ToString();
265         }
266         private bool falseIfNull(bool b)
267         {
268             return b != null && b;
269         }
270         private int zeroIfNull(int i)
271         {
272             return i == null ? 0 : i;
273         }
274         private String blankIfNull(String s)
275         {
276             return s == null ? "" : s;
277         }
278         public String getString(char arg)
279         {
280             return blankIfNull(stringArgs[arg]);
281         }
282         public int getInt(char arg)
283         {
284             return zeroIfNull(intArgs[arg]);
285         }
286         public bool getBoolean(char arg)
287         {
288             return falseIfNull(booleanArgs[arg]);
289         }
290         public bool has(char arg)
291         {
292             return argsFound.Contains(arg);
293         }
294         public bool isValid()
295         {
296             return valid;
297         }
298     }
299 
300 }

第二部分:单元测试ArgsTest.cs

  1 using System;
  2 using System.Text;
  3 using System.Collections.Generic;
  4 
  5 using Microsoft.VisualStudio.TestTools.UnitTesting;
  6 using CleanCode.Library;
  7 
  8 namespace CleanCode.Library.Test
  9 {
 10 
 11     [TestClass]
 12     public class ArgsTest
 13     {
 14 
 15         public ArgsTest()
 16         {
 17         }
 18 
 19         private TestContext testContextInstance;
 20 
 21         /// <summary>
 22         ///获取或设置测试上下文,该上下文提供
 23         ///有关当前测试运行及其功能的信息。
 24         ///</summary>
 25         public TestContext TestContext
 26         {
 27             get
 28             {
 29                 return testContextInstance;
 30             }
 31             set
 32             {
 33                 testContextInstance = value;
 34             }
 35         }
 36 
 37         #region 附加测试属性
 38         //
 39         // 编写测试时,还可使用以下附加属性:
 40         //
 41         // 在运行类中的第一个测试之前使用 ClassInitialize 运行代码
 42         // [ClassInitialize()]
 43         // public static void MyClassInitialize(TestContext testContext) { }
 44         //
 45         // 在类中的所有测试都已运行之后使用 ClassCleanup 运行代码
 46         // [ClassCleanup()]
 47         // public static void MyClassCleanup() { }
 48         //
 49         // 在运行每个测试之前,使用 TestInitialize 来运行代码
 50         // [TestInitialize()]
 51         // public void MyTestInitialize() { }
 52         //
 53         // 在每个测试运行完之后,使用 TestCleanup 来运行代码
 54         // [TestCleanup()]
 55         // public void MyTestCleanup() { }
 56         //
 57         #endregion
 58 
 59         [TestMethod]
 60         public void testCreateWithNoSchemaOrArguments()
 61         {
 62             Args args = new Args(""new String[0]);
 63             Assert.AreEqual(0, args.cardinality());
 64         }
 65 
 66         [TestMethod]
 67         public void testWithNoSchemaButWithOneArgument()
 68         {
 69             try
 70             {
 71                 new Args(""new String[] { "-x" });
 72                 //Assert.Fail();
 73             }
 74             catch (ArgsException e)
 75             {
 76                 Assert.AreEqual(ErrorCode.UNEXPECTED_ARGUMENT,
 77                             e.ErrorCode);
 78                 Assert.AreEqual('x', e.ErrorArgumentId);
 79             }
 80         }
 81 
 82 
 83         [TestMethod]
 84         public void testWithNoSchemaButWithMultipleArguments()
 85         {
 86             try
 87             {
 88                 new Args(""new String[] { "-x""-y" });
 89                 //Assert.Fail();
 90             }
 91             catch (ArgsException e)
 92             {
 93                 Assert.AreEqual(ErrorCode.UNEXPECTED_ARGUMENT,
 94                             e.ErrorCode);
 95                 Assert.AreEqual('x', e.ErrorArgumentId);
 96             }
 97         }
 98 
 99         [TestMethod]
100         public void testNonLetterSchema()
101         {
102             try
103             {
104                 new Args("*"new String[] { });
105                 //Assert.Fail("Args constructor should have thrown exception");
106             }
107             catch (ArgsException e)
108             {
109                 Assert.AreEqual(ErrorCode.INVALID_ARGUMENT_NAME,
110                           e.ErrorCode);
111                 Assert.AreEqual('*', e.ErrorArgumentId);
112             }
113         }
114 
115         [TestMethod]
116         public void testInvalidArgumentFormat()
117         {
118             try
119             {
120                 new Args("f~"new String[] { });
121                 //Assert.Fail("Args constructor should have throws exception");
122             }
123             catch (ArgsException e)
124             {
125                 Assert.AreEqual(ErrorCode.INVALID_FORMAT, e.ErrorCode);
126                 Assert.AreEqual('f', e.ErrorArgumentId);
127             }
128         }
129 
130         [TestMethod]
131         public void testSimpleBooleanPresent()
132         {
133             Args args = new Args("x"new String[] { "-x" });
134             Assert.AreEqual(1, args.cardinality());
135             Assert.AreEqual(true, args.getBoolean('x'));
136         }
137 
138         [TestMethod]
139         public void testSimpleStringPresent()
140         {
141             Args args = new Args("x*"new String[] { "-x""param" });
142             Assert.AreEqual(1, args.cardinality());
143             Assert.AreEqual(true, args.has('x'));
144             Assert.AreEqual("param", args.getString('x'));
145         }
146 
147         [TestMethod]
148         public void testMissingStringArgument()
149         {
150             try
151             {
152                 new Args("x*"new String[] { "-x" });
153                 //Assert.Fail();
154             }
155             catch (ArgsException e)
156             {
157                 Assert.AreEqual(ErrorCode.MISSING_STRING, e.ErrorCode);
158                 Assert.AreEqual('x', e.ErrorArgumentId);
159             }
160         }
161 
162         [TestMethod]
163         public void testSpacesInFormat()
164         {
165             Args args = new Args("x, y"new String[] { "-xy" });
166             Assert.AreEqual(2, args.cardinality());
167             Assert.AreEqual(true, args.has('x'));
168             Assert.AreEqual(true, args.has('y'));
169         }
170 
171         [TestMethod]
172         public void testSimpleIntPresent()
173         {
174             Args args = new Args("x#"new String[] { "-x""42" });
175             Assert.AreEqual(1, args.cardinality());
176             Assert.AreEqual(true, args.has('x'));
177             Assert.AreEqual(42, args.getInt('x'));
178         }
179 
180         [TestMethod]
181         public void testInvalidInteger()
182         {
183             try
184             {
185                 new Args("x#"new String[] { "-x""Forty two" });
186                 //Assert.Fail();
187             }
188             catch (ArgsException e)
189             {
190                 Assert.AreEqual(ErrorCode.INVALID_INTEGER, e.ErrorCode);
191                 Assert.AreEqual('x', e.ErrorArgumentId);
192                 Assert.AreEqual("Forty two", e.ErrorParameter);
193             }
194         }
195 
196         [TestMethod]
197         public void testMissingInteger()
198         {
199             try
200             {
201                 new Args("x#"new string[] { "-x" });
202                 //Assert.Fail();
203             }
204             catch (ArgsException e)
205             {
206                 Assert.AreEqual(ErrorCode.MISSING_INTEGER, e.ErrorCode);
207                 Assert.AreEqual('x', e.ErrorArgumentId);
208             }
209         }
210 
211         [TestMethod]
212         public void testSimpleDoublePresent()
213         {
214             Args args = new Args("x##"new String[] { "-x""42.3" });
215             Assert.AreEqual(1, args.cardinality());
216             Assert.AreEqual(true, args.has('x'));
217             Assert.AreEqual(42.3, args.getDouble('x'), .001);
218         }
219 
220         [TestMethod]
221         public void testInvalidDouble()
222         {
223             try
224             {
225                 new Args("x##"new String[] { "-x""Forty two" });
226                 //Assert.Fail();
227             }
228             catch (ArgsException e)
229             {
230                 Assert.AreEqual(ErrorCode.INVALID_DOUBLE, e.ErrorCode);
231                 Assert.AreEqual('x', e.ErrorArgumentId);
232                 Assert.AreEqual("Forty two", e.ErrorParameter);
233             }
234         }
235 
236         [TestMethod]
237         public void testMissingDouble()
238         {
239             try
240             {
241                 new Args("x##"new String[] { "-x" });
242                 //Assert.Fail();
243             }
244             catch (ArgsException e)
245             {
246                 Assert.AreEqual(ErrorCode.MISSING_DOUBLE, e.ErrorCode);
247                 Assert.AreEqual('x', e.ErrorArgumentId);
248             }
249         }
250     }
251 }
252 

第三部分 Args.cs 最终搞

代码

  1 /*
  2  
  3  第14章,
  4  重构步骤
  5  * 1.提取异常类ArgsException,并修改测试代码ArgsTest,支持新的异常类
  6  * 2.重构Args
  7  * 3.跑ArgsTest
  8  * 4.添加异常类型,把FormatException 添加到ArgsException中
  9  * 5.把参数类型这一维度上的变化提取到子类中(天空中的声音)。
 10  * 6.提取一个子类试试,但是用父类的名称,这里提取boolean
 11  * 7.修改setArgument函数,使用多态
 12  * 8.删除args数组,使用iterator,原来用了两个变量,现在只用了一个
 13  * 9.把setArgument函数中的多态链给去掉
 14  * 9.1 把currentArgument改成protected的
 15  * 9.2 重写各个子类的set属性
 16  * 10.添加一个double类型的类和函数
 17  * 11.在传bool类型的参数时,初值设成false如何做?
 18  */
 19 using System;
 20 using System.Collections.Generic;
 21 using System.Text;
 22 using System.Collections;
 23 using System.Security.Policy;
 24 
 25 namespace CleanCode.Library
 26 {
 27 
 28 
 29     public class Args:IDisposable
 30     {
 31         #region Fileds
 32 
 33         private String schema;
 34  
 35         private bool valid = true;
 36         private IList<char> unexpectedArguments = new List<char>();
 37 
 38         private Dictionary<char, ArgumentMarshaler> _argumentMarshalerList = new Dictionary<char, ArgumentMarshaler>();
 39  
 40         private IList<char> argsFound = new List<char>();
 41         protected IEnumerator<string>  currentArgument;
 42         private IList<string> argsList;
 43     
 44         private ErrorCode errorCode = ErrorCode.OK;
 45         #endregion
 46 
 47         #region Construcotrs
 48         public Args(string schema, string[] args)
 49         {
 50             this.schema = schema;
 51             argsList = new List<string>();
 52             for (int i = 0; i < args.Length;i++ )
 53             {
 54                 argsList.Add(args[i]);
 55             }
 56             valid = parse();
 57         }
 58         #endregion
 59 
 60         #region Properties
 61         
 62         #endregion
 63 
 64         #region Methods
 65         private bool parse()
 66         {
 67             if (0==schema.Length && 0 == argsList.Count)
 68                 return true;
 69             parseSchema();
 70             try
 71             {
 72                 parseArguments();
 73             }
 74             catch (ArgsException e)
 75             {
 76             }
 77             return valid;
 78         }
 79         private bool parseSchema()
 80         {
 81             string[] elementSet = schema.Split(new char[] { ',' });
 82             string element = string.Empty;
 83             for (int i = 0; i < elementSet.Length;i++ )
 84             {
 85                 element = elementSet[i];
 86                 if (element.Length > 0)
 87                 {
 88                     string trimmedElement = element.Trim();
 89                     parseSchemaElement(trimmedElement);
 90                 }
 91             }
 92             return true;
 93         }
 94         private void parseSchemaElement(string element)
 95         {
 96             char elementId = element[0];
 97             string elementTail = element.Substring(1);
 98             validateSchemaElementId(elementId);
 99             if (isBooleanSchemaElement(elementTail))
100                 parseBooleanSchemaElement(elementId);
101             else if (isStringSchemaElement(elementTail))
102                 parseStringSchemaElement(elementId);
103             else if (isIntegerSchemaElement(elementTail))
104             {
105                 parseIntegerSchemaElement(elementId);
106             }
107             else if (isDoubleSchemaElement(elementTail))
108             {
109                 parseDoubleSchemaElement(elementId);
110             }
111             else
112             {
113  
114                 throw new ArgsException(ErrorCode.INVALID_FORMAT,
115                                         string.Format("Argument: {0} has invalid format: {1}.",
116                                                         elementId, elementTail),
117                                         elementId);
118             }
119         }
120 
121         private void validateSchemaElementId(char elementId)
122         {
123             if (!System.Char.IsLetter(elementId))
124             {
125                 //这里为什么是不合法的参数错误?
126                 throw new ArgsException(ErrorCode.INVALID_ARGUMENT_NAME,
127                                         string.Empty,
128                                         elementId);
129     
130             }
131         }
132         private void parseBooleanSchemaElement(char elementId)
133         {
134             _argumentMarshalerList.Add(elementId, new BooleanArgumentMarshaler(true));
135         }
136         private void parseIntegerSchemaElement(char elementId)
137         {
138              _argumentMarshalerList.Add(elementId, new IntegerArgumentMarshaler(0));
139 
140         }
141         private void parseStringSchemaElement(char elementId)
142         {
143             _argumentMarshalerList.Add(elementId, new StringArgumentMarshaler(string.Empty));
144         }
145 
146         private bool isBooleanSchemaElement(String elementTail)
147         {
148             return elementTail.Length == 0;
149         }
150 
151         private bool isStringSchemaElement(String elementTail)
152         {
153             return elementTail.Equals("*");
154         }
155      
156         private bool isIntegerSchemaElement(String elementTail)
157         {
158             return elementTail.Equals("#");
159         }
160         private bool parseArguments()
161         {
162             for (currentArgument = argsList.GetEnumerator(); currentArgument.MoveNext(); )
163             {
164                 string arg = currentArgument.Current.ToString();
165                 parseArgument(arg);
166             }
167             return true;
168         }
169         private void parseArgument(String arg)
170         {
171             if (arg.StartsWith("-"))
172                 parseElements(arg);
173         }
174         private void parseElements(String arg)
175         {
176             for (int i = 1; i < arg.Length; i++)
177                 parseElement(arg[i]);
178         }
179         private void parseElement(char argChar)
180         {
181             if (setArgument(argChar))
182                 argsFound.Add(argChar);
183             else
184             {
185                 unexpectedArguments.Add(argChar);
186                 errorCode = ErrorCode.UNEXPECTED_ARGUMENT;
187                 valid = false;
188             }
189         }
190         private bool setArgument(char argChar)
191         {
192             ArgumentMarshaler m;
193 
194             try
195             {
196                 if (_argumentMarshalerList.ContainsKey(argChar))
197                 {
198                     m = _argumentMarshalerList[argChar];
199                 }
200                 else
201                 {
202                     return false;
203                 }
204 
205                 m.Set(currentArgument);
206                 
207             }
208              catch (ArgsException e)
209             {
210              
211                 valid = false;
212                 throw e;
213             }
214             return true;
215         }
216 
217         public int cardinality()
218         {
219             return argsFound.Count;
220         }
221 
222         public String usage()
223         {
224             if (schema.Length > 0)
225                 return "-[" + schema + "]";
226             else
227                 return "";
228         }
229 
230         private bool falseIfNull(bool b)
231         {
232             return null == b ? false : b;
233         }
234 
235         private int zeroIfNull(System.Int32 i)
236         {
237             return null==? 0 : i;
238         }
239 
240         private string blankIfNull(string s)
241         {
242             return null == s ? string.Empty : s;
243         }
244 
245         public string getString(char arg)
246         {
247             return blankIfNull((string)_argumentMarshalerList[arg].Value);
248         }
249 
250         public int getInt(char arg)
251         {
252             return zeroIfNull(int.Parse(_argumentMarshalerList[arg].Value.ToString()));
253         }
254 
255         public bool getBoolean(char arg)
256         {
257             return falseIfNull((bool)_argumentMarshalerList[arg].Value);
258         }
259 
260         public bool has(char arg)
261         {
262             return argsFound.Contains(arg);
263         }
264 
265         public bool isValid()
266         {
267             return valid;
268         }
269 
270         
271         #endregion
272 
273         #region  处理double参数的方法
274         private bool isDoubleSchemaElement(string elementTail)
275         {
276             return elementTail.Equals("##");
277         }
278 
279         public double getDouble(char arg)
280         {
281             return zeroDoubleIfNull( _argumentMarshalerList[arg].Value);
282         }
283 
284         private double zeroDoubleIfNull(object obj)
285         {
286             return null == obj ? 0 : double.Parse(obj.ToString());
287         }
288 
289         private void parseDoubleSchemaElement(char elementId)
290         {
291             _argumentMarshalerList.Add(elementId, new DoubleArgumentMarshaler(0));
292 
293         }
294         #endregion 
295         #region IDisposable 成员
296 
297         public void Dispose()
298         {
299           if (null!=_argumentMarshalerList)
300           {
301               _argumentMarshalerList.Clear();
302           }
303         }
304 
305         #endregion
306     }
307 
308     public interface ArgumentMarshaler
309     {
310         object Value
311         {
312             get;
313         }
314         void Set(IEnumerator<string> currentArgument);
315     }
316 
317     public class BooleanArgumentMarshaler:ArgumentMarshaler
318     {
319         private Boolean _boolArguemnt;
320         
321         public BooleanArgumentMarshaler(bool boolArguemnt)
322         {
323             this._boolArguemnt = boolArguemnt;
324         }
325 
326         
327         #region ArgumentMarshaler 成员
328 
329         object ArgumentMarshaler.Value
330         {
331             get { return _boolArguemnt; }
332             
333         }
334 
335         void ArgumentMarshaler.Set(IEnumerator<string> currentArgument)
336         {
337             try
338             {
339                
340                 _boolArguemnt =true;
341             }
342             catch (IndexOutOfRangeException e)
343             {
344 
345                 ErrorCode errorCode = ErrorCode.INVALID_BOOLEAN;
346   
347                 throw new ArgsException(errorCode, string.Empty);
348             }
349         
350         }
351        
352         #endregion
353 
354 
355     }
356 
357     public class StringArgumentMarshaler : ArgumentMarshaler
358     { 
359         private string _stringArguemnt;
360         public StringArgumentMarshaler(string stringArguemnt)
361         {
362             this._stringArguemnt = stringArguemnt;
363         }
364         object ArgumentMarshaler.Value 
365         {
366             get { return _stringArguemnt; }
367              
368         }
369         void ArgumentMarshaler.Set(IEnumerator<string> currentArgument)
370         {
371             currentArgument.MoveNext();
372             try
373             {
374 
375                 _stringArguemnt= currentArgument.Current;
376             }
377             catch (InvalidOperationException e)
378             {
379 
380                 ErrorCode errorCode = ErrorCode.MISSING_STRING;
381                 char errorArgumentId = '\0';
382                 throw new ArgsException(errorCode, string.Empty, errorArgumentId);
383             }
384         
385         }
386     }
387     public class IntegerArgumentMarshaler : ArgumentMarshaler
388     {
389         private System.Int32 _intArguemnt;
390         public IntegerArgumentMarshaler(int intArguemnt)
391         {
392             this._intArguemnt = intArguemnt;
393         }
394 
395         object ArgumentMarshaler.Value 
396         {
397             get { return _intArguemnt; }
398           
399         }
400 
401         void ArgumentMarshaler.Set(IEnumerator<string> currentArgument)
402         {
403             try
404             {
405                 currentArgument.MoveNext();
406                 _intArguemnt = int.Parse(currentArgument.Current.ToString());
407             }
408             catch (System.NullReferenceException ne)
409             {
410                   
411                 throw new ArgsException(ErrorCode.MISSING_INTEGER);
412             }
413             catch (InvalidOperationException e)
414             {
415 
416                 ErrorCode errorCode = ErrorCode.MISSING_INTEGER;
417                 throw new ArgsException(errorCode, string.Empty);
418             }
419 
420             catch (InvalidCastException ice)
421             {
422                 throw new ArgsException(ErrorCode.INVALID_FORMAT);
423             }
424             catch (FormatException fx) 
425             { 
426                 throw new ArgsException(ErrorCode.INVALID_FORMAT); 
427             }
428         }
429     }
430 
431       public class DoubleArgumentMarshaler : ArgumentMarshaler
432     {
433         private double _argument;
434         public DoubleArgumentMarshaler(double argument)
435         {
436             this._argument = argument;
437         }
438 
439         object ArgumentMarshaler.Value 
440         {
441             get { return _argument; }
442           
443         }
444 
445         void ArgumentMarshaler.Set(IEnumerator<string> currentArgument)
446         {
447             try
448             {
449                 currentArgument.MoveNext();
450                 _argument = double.Parse(currentArgument.Current);
451             }
452             catch (System.ArgumentNullException ex)
453             {
454                   
455                 throw new ArgsException(ErrorCode.MISSING_DOUBLE);
456             }
457             catch (InvalidOperationException e)
458             {
459 
460                 ErrorCode errorCode = ErrorCode.MISSING_DOUBLE;
461                 throw new ArgsException(errorCode, string.Empty);
462             }
463 
464             catch (InvalidCastException ice)
465             {
466                 throw new ArgsException(ErrorCode.INVALID_FORMAT);
467             }
468             catch (FormatException fx) 
469             {
470                 throw new ArgsException(ErrorCode.INVALID_FORMAT); 
471             }
472         }
473     }
474 }

 第四部分 异常类 ArgsException.cs

代码

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Text;
  4 
  5 namespace CleanCode.Library
  6 {
  7 
  8     public enum ErrorCode
  9     {
 10         OK, MISSING_STRING, MISSING_INTEGER, INVALID_INTEGER, INVALID_BOOLEAN, UNEXPECTED_ARGUMENT,
 11         INVALID_FORMAT, INVALID_ARGUMENT_NAME, INVALID_DOUBLE, MISSING_DOUBLE
 12     }
 13     public class ArgsException: Exception
 14     {
 15        
 16          #region Fileds
 17          private ErrorCode _errorCode;
 18          private string _msg;
 19          private char _errorArgumentId = '\0';
 20          private String _errorParameter = "TILT";
 21          #endregion
 22 
 23          #region Constructors
 24          public ArgsException()
 25          {
 26              _msg = string.Empty;
 27              _errorCode = ErrorCode.OK;
 28          }
 29 
 30          public ArgsException(ErrorCode errCode):this(errCode,string.Empty)
 31          {
 32              _msg = string.Empty;
 33              _errorCode = errCode;
 34          }
 35 
 36          public ArgsException(ErrorCode errCode, string message)
 37              : base(message)
 38          {
 39              _msg = message;
 40              _errorCode = errCode;
 41          }
 42          public ArgsException(ErrorCode errCode, string message, char errorArgumentId)
 43              : this(errCode, message)
 44          {
 45              _errorArgumentId = errorArgumentId;
 46          }
 47 
 48          public ArgsException(ErrorCode errCode, string message, char errorArgumentId, string errorParameter)
 49              : this(errCode, message, errorArgumentId)
 50          {
 51              _errorParameter = errorParameter;
 52          }
 53 
 54          #endregion
 55          
 56          #region Properties
 57          public ErrorCode ErrorCode
 58          {
 59              get { return _errorCode; }
 60          }
 61 
 62          public char ErrorArgumentId 
 63          {
 64              get { return this._errorArgumentId; }
 65          }
 66 
 67          public string ErrorParameter
 68          {
 69              get { return _errorParameter; }
 70          }
 71          #endregion
 72 
 73 
 74          #region Message
 75          public String errorMessage()
 76          {
 77              switch (_errorCode)
 78              {
 79                  case ErrorCode.OK:
 80                      throw new Exception("TILT: Should not get here.");
 81                  case ErrorCode.UNEXPECTED_ARGUMENT:
 82                      return "Unexcepted argument exception.";
 83                  case ErrorCode.MISSING_STRING:
 84                      return String.Format("Could not find string parameter for -{0}.",
 85                                           _errorArgumentId);
 86                  case ErrorCode.INVALID_INTEGER:
 87                      return String.Format("Argument -{0} expects an integer but was '{1}'.",
 88                                           _errorArgumentId, _errorParameter);
 89                  case ErrorCode.MISSING_INTEGER:
 90                      return String.Format("Could not find integer parameter for -{0}.",
 91                                           _errorArgumentId);
 92 
 93                  case ErrorCode.INVALID_DOUBLE:
 94                      return String.Format("Argument -{0} expects an double but was '{1}'.",
 95                                           _errorArgumentId, _errorParameter);
 96                  case ErrorCode.MISSING_DOUBLE:
 97                      return String.Format("Could not find double parameter for -{0}.",
 98                                           _errorArgumentId);
 99              }
100              return string.Empty;
101          }
102 
103         
104         #endregion
105      }
106 }
107 

源码下载