基本步骤:
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方法
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是执行具体操作的方法。这里编写的规则只针对属性。
{
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 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


< 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