Анализ кода CA1063 срабатывает при выводе из IDisposable и обеспечении реализации в базовом классе - PullRequest
37 голосов
/ 19 января 2012

У меня есть код, который вызовет предупреждение анализа кода CA1063:

CA1063: Microsoft.Design: удалить IDisposable из списка интерфейсов, реализованных в «Функциональности», и вместо этого переопределить реализацию Dispose базового класса.

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

Вкратце, у меня есть интерфейс IFunctionality, производный от IDisposable. Класс Functionality реализует IFunctionality, но наследуется от класса Reusable, чтобы иметь возможность повторно использовать код som. Класс Reusable также происходит от IDisposable.

public class Reusable : IDisposable {

  ~Reusable() {
    Dispose(false);
  }

  public void Dispose() {
    Dispose(true);
    GC.SuppressFinalize(this);
  }

  protected virtual void Dispose(Boolean disposing) {
    // ...
  }

  public void DoSomething() {
    // ...
  }

}

public interface IFunctionality : IDisposable {

  void DoSomething();

  void DoSomethingElse();

}

public class Functionality : Reusable, IFunctionality {

  public void DoSomethingElse() {
    // ...
  }

#if WORK_AROUND_CA1063
  // Removes CA1063
  protected override void Dispose(Boolean disposing) {
    base.Dispose(disposing);
  }
#endif

}

Я могу избавиться от предупреждения, переопределив Dispose на Functionality и вызвав базовый класс Dispose, даже если это не изменит семантику кода.

Так есть ли что-то в IDisposable в этом контексте, которое я упустил, или это просто CA1063, который пропускает зажигание для этой конкретной конструкции?

Я знаю, что могу подавить CA1063, но правило довольно широкое, и я не хочу пропустить какие-либо другие проблемы с реализацией IDisposable, о которых сообщается в этом правиле.

Ответы [ 3 ]

39 голосов
/ 19 января 2012

Это ложное срабатывание из-за незначительной ошибки в самом правиле. При попытке выяснить, реализует ли класс повторно IDisposable (после выяснения, что существует реализация базового класса, которая может быть переопределена), он только проверяет, включают ли интерфейсы класса IDisposable. К сожалению, список интерфейсов, который отображается в метаданных сборки, включает «разнесенный» список интерфейсов, включая любые интерфейсы, унаследованные через интерфейсы, которые класс явно реализует в исходном коде C #. Это означает, что FxCop видит объявление, которое выглядит следующим образом для вашего класса Functionality:

public class Functionality : Reusable, IFunctionality, IDisposable
{
    ...
}

Учитывая это представление метаданных, правило ImplementIDisposableCorrectly должно быть немного более интеллектуальным о том, как оно пытается определить, действительно ли класс повторно реализует IDisposable (например, путем поиска явной реализации Dispose (), если базовый класс имеет переопределенный Dispose (bool)). Однако, учитывая, что правило этого не делает, ваш лучший подход - подавлять ложные срабатывания.

Кстати, я бы настоятельно рекомендовал рассмотреть возможность использования SuppressMessageAttribute для подавления ложных срабатываний вместо вашего текущего подхода к условной компиляции. e.g.:

[SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly",
    Justification = "False positive.  IDisposable is inherited via IFunctionality.  See /5218650/analiz-koda-ca1063-srabatyvaet-pri-vyvode-iz-idisposable-i-obespechenii-realizatsii-v-bazovom-klasse for details.")]
public class Functionality : Reusable, IFunctionality
{
    ...
}

Кроме того, вы можете серьезно подумать об избавлении от финализатора ...

4 голосов
/ 19 января 2012

Ваш «обходной путь» - правильный шаблон для производного класса, который снова реализует IDisposable.

Но я думаю, вы должны пересмотреть дизайн IFunctionality : IDisposable.Является ли одноразовое использование действительно проблемой IFunctionality?Я думаю, что это решение принадлежит классу-исполнителю.

1 голос
/ 19 января 2012

Это связано с использованием IDisposable, а не с самим интерфейсом. Вы просто реализуете рекомендуемый шаблон для его использования, предоставляя и переопределяя защищенный метод Dispose(bool) - это не является частью самого интерфейса.

Если ваш метод переопределения на самом деле ничего не добавляет, тогда нет проблем с его опусканием. Предупреждение CA1063 призван подчеркнуть проблему, но если вы знаете, что в вашем случае на самом деле нет ресурсов, которые можно было бы утилизировать, вы можете обойти ее, либо предоставив пустую реализацию, либо исключив это конкретное правило для этого файл.

Это можно сделать с помощью атрибута [SuppressMessage].

...