Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

C#. Сортировка членов типа с поддержкой Resharper

Anna | 17.06.2014 | нет комментариев

Существуют некоторые соглашения касаемые конструкции класса, и того, в каком порядке обязаны располагаться его члены.
Скажем, правила которые использует StyleCop, допустимо, в вашей компании есть свои личные.
Поддерживать конструкцию вручную достаточно трудно, уныло и отнимает много времени, исключительно когда в классе достаточно огромное число свойств, полей, способов и.т.д.
В этом посте речь пойдет о том, как с поддержкой Resharper автоматизировать данный процесс.

Задача

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

Каша

        private bool fieldBool;

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public string SomeProperty { get; set; }

        public string SecondProperty { get; set; }

        public void DoSomething()
        {
        }

        private string fieldString;

        public DemoClass(bool fieldBool, string fieldString)
        {
            this.fieldBool = fieldBool;
            this.fieldString = fieldString;
        }

        public static void DoSomethingStatic()
        {
        }

        public bool Equals(DemoClass other)
        {
            throw new NotImplementedException();
        }

 

Сортировка по умолчанию

Но, к счастью, в Resharper есть инструмент Cleanup Code. И если запустить его со включенной опцией Member Reordering, мы получим класс с упорядоченными членами.

Позже

    public class DemoClass : IEquatable<DemoClass>
    {
        private bool fieldBool;
        private string fieldString;

        public DemoClass(bool fieldBool, string fieldString)
        {
            this.fieldBool = fieldBool;
            this.fieldString = fieldString;
        }

        public string SomeProperty { get; set; }

        public string SecondProperty { get; set; }

        public bool Equals(DemoClass other)
        {
            throw new NotImplementedException();
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public void DoSomething()
        {
        }

        public static void DoSomethingStatic()
        {
        }
    }

 

Настраиваемые правила

Но что если сортировка по умолчанию нас не устраивает, и отличается от той, которая принята у вас в качестве эталона?
В этом случае Resharper разрешает переопределить правила используемые по умолчанию.
Идем в ReSharper -> Options -> Code Editing -> C# -> Type Member Layout и включаем Custom Layout.
Перед нами откроется XML тот, что описывает порядок сортировки.

Пример

<Patterns xmlns="urn:shemas-jetbrains-com:member-reordering-patterns">
  <Pattern>
    <!--static fields and constants-->
    <Entry>
      <Match>
        <Or Weight="100">
          <Kind Is="constant"/>
          <And>
            <Kind Is="field"/>
            <Static/>
          </And>
        </Or>
      </Match>
      <Sort>
        <Kind Order="constant field"/>
      </Sort>
    </Entry>
    <Entry>
      ...
    </Entry>
  </Pattern>
  <Pattern>
    ...
  <Pattern>
</Patterns>

Элемент Patterns родительский элемент, может содержать внутри себя уйма элементов Pattern, тот, что, в свою очередь, может содержать уйма элементов Entry.
Элемент Entry представляет собой запись с которой мы будем осуществлять какие-то действия. Порядок Entry в элементе Pattern влияет на порядок элементов.
Представим нам необходим дальнейший порядок: конструкторы, способы, остальные члены.
Для этого мы можем написать такое правило:

Пример

<?xml version="1.0" encoding="utf-8"?>

<Patterns xmlns="urn:shemas-jetbrains-com:member-reordering-patterns">
  <Pattern>
    <Entry>
      <Match>
        <Kind Is="constructor" />
      </Match>
    </Entry>
    <Entry>
      <Match>
        <Kind Is="method" />
      </Match>
    </Entry>
    <Entry />
  </Pattern>
</Patterns>

Всякий элемент Entry содержит вложенный элемент Match, в котором мы описываем, что мы ищем. Мы можем задать больше подробные правила для поиска, и пользоваться логическими операторами Or, And, Not и операндами:

<Kind Is=”…”/> Аттрибут Is может быть class, struct, interface, enum, delegate, type, constructor, destructor, property, indexer, method, operator, field, constant, event, member
<Name Is=”…” [IgnoreCase=«true/false»] /> Аттрибут Is может содержать регулярное выражение
<HasAttribute CLRName=”…” [Inherit=«true/false»] /> Аттрибут CLRName может содержать регулярное выражение
<Access Is=”…”/> Аттрибут Is может быть public, protected, internal, protected-internal, private
<Static/>
<Abstract/>
<Virtual/>
<Override/>
<Sealed/>
<Readonly/>
<ImplementsInterface CLRName=”…”/> Аттрибут CLRName может содержать регулярное выражение
<HandlesEvent />

Так же, всякий элемент Entry может содержать Sort, что влияет на сортировку обнаруженных членов в пределах одного Entry.
Скажем, нам нужно обнаружить статические поля и константы и расположить их в самом начале класса. А так же отсортировать их по имени. Для этого нам нужно добавить следующую запись в предисловие паттерна.

Пример

    <Entry>
      <Match>
        <Or>
          <Kind Is="constant" />
          <And>
            <Kind Is="field" />
            <Static />
          </And>
        </Or>
      </Match>
      <Sort>
        <Name />
      </Sort>
    </Entry>

 

Группировка

Так же поддерживается группировка.
Возможен, что способы нужно разделять на неподвижные и экземплярные, сортировать по имени и оборачивать в соответствующие регионы. Для этого нам нужно сделать два разных элемента Entry с дочерним элементом Group:

Пример

    <Entry>
      <Match>
        <And>
          <Kind Is="method" />
          <Static/>
        </And>
      </Match>
      <Group Region="Static methods" />
    </Entry>
    <Entry>
      <Match>
        <Kind Is="method" />
      </Match>
      <Group Region="Instance methods" />
    </Entry>

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

Пример

    <Entry>
      <Match>
        <Kind Is="member" />
        <ImplementsInterface/>
      </Match>
      <Sort>
        <ImplementsInterface/>
      </Sort>
      <Group>
        <ImplementsInterface Region="${ImplementsInterface} Members" />
      </Group>
    </Entry>

В этом примере, переменная ${ImplementsInterface} будет равна наименованию интерфейса.
Также, элемент Pattern поддерживает аттрибут RemoveAllRegions, тот, что может быть установлен в true либо false (по умолчанию false). Если он установлен в true, то при группировке, будут удалены все регионы которые были до нее.

Вес

Что если условию (Match) соотвествуют сразу несколько типов?
Представим мы хотим сгруппировать все приватные члены в один регион, помимо способов. Мы могли бы написать следующее правило:

Пример

    <Entry>
      <Match>
        <Access Is="private" />
      </Match>
      <Group Region="Private members" />
    </Entry>
    <Entry>
      <Match>
        <Kind Is="method" />      
      </Match>
      <Group Region="All methods" />
    </Entry>

Но, если у нас есть приватный способ, то он попадает под оба правила. Первое правило применится прежде, второе условие не будет исполнено. И в результате, регион тот, что будет содержать приватные члены, будет так же содержать и приватные способы.
Всякий удачно исполненный операнд дает 1 очко веса по умолчанию и эти очки суммируются. В данном случае, в всяком из элементов по одному операнду: <Access Is=«private» /> и <Kind Is=«method» /> соотвественно. Если мы хотим, Дабы второе правило выполнилось, мы можем применять аттрибут Weight на операнде.

Пример

    <Entry>
      <Match>
        <Access Is="private" />
      </Match>
      <Group Region="Private members" />
    </Entry>
    <Entry>
      <Match>
        <Kind Is="method" Weight="5"/>      
      </Match>
      <Group Region="All methods" />
    </Entry>

Таким образом, второе событие будет иметь больший вес, и все сгруппируется так, как было задумано.

Паттерны

В самом начале, я говорил об элементе Pattern, он так же может содержать элемент Match и данный элемент определяет где будут делать правила которые содержит паттерн.
А сейчас, предположим ситуацю, когда во всех интерфейсах, нам нужна иная сортировка. В такой обстановки мы могли бы сделать обособленный элемент Pattern

Пример

  <Pattern>
      <Match>
        <Kind Is="interface" />
      </Match>
      ...
  </Pattern>

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

Завершение

В этом посте, я хотел показать, некоторые из вероятностей Resharper, которые, допустимо сделают вашу жизнь легче.
Данный пост не претендует на исчерпывающую документацию по данному вопросу.
Источники:

 

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB