基本步骤:
1、 新建Dll项目,引用StyleCop.Dll和StyleCop.Csharp.Dll。
2、 自定义的规则校验类从SourceAnalyzer继承,必须实现public virtual void AnalyzeDocument(CodeDocument document)方法。
3、 在需要触发违反规则的地方使用方法AddViolation。
4、 在项目中增加一个xml嵌入资源,该资源的文件名必须与校验类同名。该xml可以定义校验类显示在StyleCop Setting的规则、规则描述和参数等。
5、 编译成功,将Dll复制到StyleCopy的目录下。
StyleCop的Documnetaion Rules对代码的文档有一系列的要求,譬如SA1623 要求属性的备注文档开头必须注明whether the property exposes get or set accessors。其校验的实现方式是在备注的开头判断是否有属性访问权对应的Get/ Set字符。中文用户是不大适应用Get和Set作备注的,因此以下一个简单例子实现一个判断中文备注的规则,代替原有的SA1623。
由于每个Rule都必须有唯一的RuleName和RuleID。RuleName只是用于内部,不被用户看见。RuleID由2位大写字母开头和4位数字组成。SA1623就是RuleID。例子使用MY1623与StyleCop原有的RuleID相对。
覆盖AnalyzeDocument方法
1 public override void AnalyzeDocument(CodeDocument document) 2 { 3 Param.RequireNotNull(document, " document " ); 4 CsDocument document2 = (CsDocument)document; 5 if ((document2.RootElement != null ) && ! document2.RootElement.Generated) 6 { 7 document2.WalkDocument( new CodeWalkerElementVisitor < object > ( this .CheckDocumentationForElement), null ); 8 } 9 }
WalkDocumnet方法是遍历代码中的各个节点(方法、属性等)。CheckDocumentationForElementelement.ElementType == ElementType.Property是执行具体操作的方法。这里编写的规则只针对属性。
private bool CheckDocumentationForElement(CsElement element, CsElement parentElement, Object settings) { if ( base .Cancel) { return false ; } if ( ! element.Generated) { if (element.ElementType == ElementType.Property) { this .ParseHeader(element, element.Header, element.LineNumber, false ); } } return true ; }private readonly string headerSummaryForGetAndSetAccessor = " 可读写 " ; private readonly string headerSummaryForGetAccessor = " 只读 " ; private readonly string headerSummaryForSetAccessor = " 只写 " ; private void ParseHeader(CsElement element, XmlHeader header, int lineNumber, bool partialElement) { XmlDocument doc = this .LoadHeaderIntoDocument(element, header, lineNumber); if ((doc != null ) && (element.ElementType == ElementType.Property)) { this .CheckPropertySummaryFormatting(element as Property, doc); } } private XmlDocument LoadHeaderIntoDocument(CsElement element, XmlHeader header, int lineNumber) { XmlDocument document = new XmlDocument(); try { string xml = " <root> " + header.Text + " </root> " ; document.LoadXml(xml); } catch (XmlException exception) { base .AddViolation(element, lineNumber, Rules.DocumentationMustContainValidXml, new object [] { exception.Message }); document = null ; } catch (Exception exception) { base .AddViolation(element, lineNumber, Rules.DocumentationMustContainValidXml, new object [] { exception.Message }); document = null ; } return document; } private void CheckPropertySummaryFormatting(Property property, XmlDocument doc) { XmlNode node = doc.SelectSingleNode( " root/summary " ); if (node != null ) { bool flag = ((property.ReturnType.Text == " bool " ) || (property.ReturnType.Text == " Boolean " )) || (property.ReturnType.Text == " System.Boolean " ); if (property.GetAccessor != null ) { if ((property.SetAccessor == null ) || ((property.SetAccessor.AccessModifier != property.AccessModifier) && (((property.AccessModifier == AccessModifierType.Private) || (property.SetAccessor.AccessModifier != AccessModifierType.Private)) || property.SetAccessor.Declaration.ContainsModifier( new CsTokenType[] { CsTokenType.Private })))) { string str2 = headerSummaryForGetAccessor; string str3 = node.InnerText.TrimStart( new char [ 0 ]); if ( ! CompareTextWithColon(str3, str2)) { base .AddViolation(property, Rules.PropertySummaryDocumentationMustMatchAccessors, new object [] { str2 }); } } else { string str = headerSummaryForGetAndSetAccessor; if ( ! CompareTextWithColon(node.InnerText.TrimStart( new char [ 0 ]), str)) { base .AddViolation(property, Rules.PropertySummaryDocumentationMustMatchAccessors, new object [] { str }); } } } else if (property.SetAccessor != null ) { string str5 = headerSummaryForSetAccessor; if ( ! CompareTextWithColon(node.InnerText.TrimStart( new char [ 0 ]), str5)) { base .AddViolation(property, Rules.PropertySummaryDocumentationMustMatchAccessors, new object [] { str5 }); } } } } private bool CompareTextWithColon( string input, string pattern) { return Regex.IsMatch(input, pattern + " [::] " , RegexOptions.Singleline); }
对应的资源xml
View Code <? xml version="1.0" encoding="utf-8" ?> < SourceAnalyzer Name ="My Documentation Rules" > < Description > Rules which verify the content and formatting of code documentation. </ Description > < Rules > < Rule Name ="DocumentationMustContainValidXml" CheckId ="HD1603" > < Context > The documentation header is composed of invalid Xml: {0} </ Context > < Description > Indicates that a documentation header is composed of invalid Xml and cannot be parsed. </ Description > </ Rule > < Rule Name ="PropertySummaryDocumentationMustMatchAccessors" CheckId ="HD1623" > < Context > 属性的摘要文档说明必须使用“{0}”开头 </ Context > < Description > Validates that a property's summary description text begins with the correct syntax, depending upon whether the property exposes get or set accessors. </ Description > </ Rule > </ Rules > </ SourceAnalyzer >其中Description节点的内容是显示在Stylecop Setting窗口下方的文字。Context是违反规则时,显示在VS 错误列表的文字。
附上代码:/Files/Byeah/MyFirstRule.zip
下一篇:《编写StyleCop自定义规则教程(二)---校验规则增加配置参数 》
转载于:https://www.cnblogs.com/Byeah/archive/2011/06/27/2091222.html
相关资源:Microsoft.StyleCop安装包(带示例、说明文档等)