Как писать высококлассный код. Часть пятая. StyleCop

среда, 9 февраля 2011, Александр Краковецкий

После небольшой паузы, связанной с подготовкой и выступлением на .NET Saturday, я продолжаю цикл статей под общим названием «Как писать высококлассный код». Сегодняшняя статья будет посвящена инструменту под названием StyleCop.

StyleCop – младшая сестра или брат (кому как удобней) инструмента FxCop, о котором я писал в предыдущей части. Но, в отличии от FxCop, StyleCop обладает большим количеством дополнительных правил, связанных с оформлением кода.

Скачать инструмент можно по адресу http://stylecop.codeplex.com/, работает только для C# кода. На момент написания статьи последней стабильной версией инструмента является версия 4.4.0.

После установки StyleCop в Visual Studio появляется дополнительный функционал:

alt text

Все правила делятся на несколько групп:

  • Documentation
  • Layout
  • Maintainability
  • Naming
  • Ordering
  • Readability
  • Spacing

Включить или выключить правила можно в окне свойств:

link text

Рассмотрим основные правила, с которыми сталкиваются разработчики.

Documentation rules

*MustBeDocumented – все элементы (методы, переменные и т.д. должны быть задокументированы, включая приватные члены).

SA1625: ElementDocumentationMustNotBeCopiedAndPasted – описание переменных не должно совпадать:

/// <summary>
/// Joins a first name and a last name together into a single string.
/// </summary>
/// <param name="firstName">Part of the name.</param>
/// <param name="lastName">Part of the name.</param>
/// <returns>The joined names.</returns>
public string JoinNames(string firstName, string lastName)
{
    return firstName + " " + lastName;
}

SA1633: FileMustHaveHeader – все файлы должны содержать шапку:

//-----------------------------------------------------------------------
// <copyright file="Widget.cs" company="Sprocket Enterprises">
//     Copyright (c) Sprocket Enterprises. All rights reserved.
// </copyright>
// <author>John Doe</author>
//-----------------------------------------------------------------------

Причем название файла должно совпадать со значением в file (SA1638: FileHeaderFileNameDocumentationMustMatchFileName).

SA1642: ConstructorSummaryDocumentationMustBeginWithStandardText – описание конструктора должно соответствовать шаблону "Initializes a new instance of the {class name} class.":

/// <summary>
/// Initializes a new instance of the <see cref="Customer"/> class.
/// </summary>
public Customer()
{
}

То же самое для деструкторов (SA1643: DestructorSummaryDocumentationMustBeginWithStandardText).

Layout rules

SA1500: CurlyBracketsForMultiLineStatementsMustNotShareLine – скобки должны располагаться на отдельных линиях, т.е. вместо

public object Method()
    {
        lock (this) {
            return this.value;
        }
    }

должно быть

public object Method()
    {
        lock (this) 
        {
            return this.value;
        }
    }

Между методом и комментариями не должно быть пустых линий (SA1506: ElementDocumentationHeadersMustNotBeFollowedByBlankLine), как здесь:

/// <summary>
/// Gets a value indicating whether the control is enabled.
/// </summary>

public bool Enabled
{
    get { return this.enabled; }
}

То же самое для кода внутри методов (SA1507: CodeMustNotContainMultipleBlankLinesInARow).

Остальные правила также касаются, в основном, необходимости удаления пустых линий.

Maintainability rules

SA1119: StatementMustNotUseUnnecessaryParenthesis – код не должен содержать лишние скобки:

int x = (5 + b);
string y = (this.Method()).ToString();
return (x.Value);

правильно:

int x = 5 + b;
string y = this.Method().ToString();
return x.Value;

Все методы и свойства должны иметь явно указанный идентификатор доступа (SA1400: AccessModifierMustBeDeclared).

Один файл может содержать только один одноименный класс (SA1402: FileMayOnlyContainASingleClass).

Для математических выражений необходимо четко указывать порядок выполнения с помощью дополнительных скобок (SA1407: ArithmeticExpressionsMustDeclarePrecedence). Т.е. такой код:

int x = 5 + y * b / 6 % z - 2;

нужно переписать таким образом:

int x = 5 + (y * ((b / 6) % z)) - 2;

Код не должен содержать не используемый код (SA1409: RemoveUnnecessaryCode):

Naming rules

Если коротко, то названия методов, классов должны начинаться с заглавной буквы (SA1300: ElementMustBeginWithUpperCaseLetter), а интерфейсы – с буквы “I” (SA1302: InterfaceNamesMustBeginWithI). Нельзя использовать префиксы m_ или s_ в именах переменных (SA1308: VariableNamesMustNotBePrefixed), а также нельзя использовать символ подчеркивания (SA1309: FieldNamesMustNotBeginWithUnderscore, SA1310: FieldNamesMustNotContainUnderscore).

Ordering rules

Одно из самых обсуждаемых правил – все usings должны размещаться внутри namespaces.

Неправильно:

using System;
using Guid = System.Guid;

namespace Microsoft.Sample
{
    public class Program
    {
    }
}

Правильно:

namespace Microsoft.Sample
{
    using System;
    using Guid = System.Guid;

    public class Program
    {
    }
}

Если говорить о причине такого правила, то она связана с возможными трудностями при работе с алиасами.

Например, такой код успешно скомпилируется:

using Guid = System.Guid;

namespace Microsoft.Sample
{
    public class Guid
    {
        public Guid(string s)
        {
        }
    }

    public class Program
    {
        public static void Main(string[] args)
        {
            Guid g = new Guid("hello");
        }
    }
}

Но здесь непонятно, какой из Guid будет использоваться.

Такой код вызовет предупреждение CS0576: Namespace 'Microsoft.Sample' contains a definition conflicting with alias 'Guid':

namespace Microsoft.Sample
{
    using Guid = System.Guid;

    public class Guid
    {
        public Guid(string s)
        {
        }
    }

    public class Program
    {
        public static void Main(string[] args)
        {
            Guid g = new Guid("hello");
        }
    }
}

Но поможет избежать путаницы в наименованиях.

Все элементы должны располагаться в нужном порядке внутри исходного файла (SA1201: ElementsMustAppearInTheCorrectOrder):

  • Extern Alias Directives
  • Using Directives
  • Namespaces
  • Delegates
  • Enums
  • Interfaces
  • Structs
  • Classes

В классе, структуре, интерфейсе порядок должен быть такой:

  • Fields
  • Constructors
  • Finalizers (Destructors)
  • Delegates
  • Events
  • Enums
  • Interfaces
  • Properties
  • Indexers
  • Methods
  • Structs
  • Classes

Элементы должны быть отсортированы о уровню доступа (SA1202: ElementsMustBeOrderedByAccess):

  • public
  • internal
  • protected internal
  • protected
  • private

Все usings должны быть отсортированы, а неиспользуемые – удалены (SA1210: UsingDirectivesMustBeOrderedAlphabeticallyByNamespace).

Readability rules

Необходимо использовать префикс this для доступа к членам классов (SA1101: PrefixLocalCallsWithThis). Остальные правила такого типа связаны с позиционированием параметров, регионов, выражений и т.д.

Необходимо использовать string.Empty вместо пустой строки (SA1122: UseStringEmptyForEmptyStrings).

Необходимо использовать встроенные алиасы (int, string вместо Int32, String и т.д.) (SA1121: UseBuiltInTypeAlias).

Spacing rules

В этой группе много правил, связанных с табуляцией и пробелами. Если кратко, то код не должен содержать лишние пробелы, а использование табуляции запрещено (SA1027: TabsMustNotBeUsed).

Отключение правил в коде

Для того, чтобы не проверять некий код на определенное правило, можно воспользоваться специальным атрибутом:

[SuppressMessage("Rule Category, "Rule Id", "Justification")]

где:

  • Rule Category – пространство имен StyleCop, в котором объявлено. Например, Microsoft.StyleCop.CSharp.DocumentationRules;
  • Rule Id –идентификатор правила в формате shortname:longname. Например, SA1600:ElementsMustBeDocumented;
  • Justification – текст, который будет использован для объяснения причины, почему то или иное правило было пропущено.

Пример:

[SuppressMessage("Microsoft.StyleCop.CSharp.DocumentationRules", "SA1600:ElementsMustBeDocumented")]
public class MyUndocumentedClass
{
    public void MyUndocumentedMethod
    {
    }
} 

Если вы хотите запретить все правила в заданном пространстве имен, то это можно сделать таким образом:

public class OuterClass
{
    [SuppressMessage("Microsoft.StyleCop.CSharp.DocumentationRules", "*")]
    public class InnerClass
    {
        public void MyUndocumentedMethod
        {
        }
    }
}

StyleCop for Resharper

Кроме, собственно, StyleCop, есть еще один продукт под названием StyleCop for Resharper. Как нетрудно догадаться из названия, этот инструмент служит для интеграции правил с Resharper.

Сайт: http://stylecopforresharper.codeplex.com/

В целом, использование StyleCop делает ваш код красивым и простым с точки зрения читабельности и оформления, что очень важно для последовательной поддержки.

Литература:

Компании из статьи


Microsoft Украина


Сайт:
http://www.microsoft.com/ukr/ua/

Microsoft Украина Украинское подразделение компании Microsoft.

Ищите нас в интернетах!

Комментарии

Свежие вакансии