Нечистый метод вызывается только для чтения - PullRequest
80 голосов
/ 29 марта 2012

Я использую Visual Studio 2010 + Resharper , и он показывает предупреждение по следующему коду:

if (rect.Contains(point))
{
    ...
}

rect - это readonly Rectangle field, и Resharper показывает мне это предупреждение:

«Нечистый метод вызывается для поля типа« только чтение »».

Что такое нечистые методы и почемуэто предупреждение мне показывают?

Ответы [ 5 ]

95 голосов
/ 29 марта 2012

Прежде всего, ответы Джона, Майкла и Джареда по существу правильные, но у меня есть еще несколько вещей, которые я хотел бы добавить к ним.

Что подразумевается под "нечистым" методом?

Чистые методы легче охарактеризовать.«Чистый» метод имеет следующие характеристики:

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

Например, Math.Cos - это чистый метод.Его выход зависит только от его входа, и вход не изменяется при вызове.

Нечистый метод - это метод, который не является чистым.

Каковы некоторые из опасностейпрохождения только для чтения нечистых методов?

Есть два, которые приходят на ум.Первый - это тот, на который указывают Джон, Майкл и Джаред, и именно об этом вас предупреждает Решарпер.Когда вы вызываете метод в структуре, мы всегда передаем ссылку на переменную, которая является получателем, в случае, если метод хочет изменить переменную.

Так что, если вы вызываете такой метод для значения,а не переменная?В этом случае мы создаем временную переменную, копируем в нее значение и передаем ссылку на переменную.

Переменная только для чтения считается значением, поскольку ее нельзя преобразовать вне конструктора.Таким образом, мы копируем переменную в другую переменную, и нечистый метод, возможно, мутирует копию, когда вы намереваетесь изменить ее переменную.1031 *.Существует также опасность передачи структуры, содержащей поле только для чтения.Структура, которая содержит поле только для чтения, является обычной практикой, но по существу она выписывает чек на то, что система типов не имеет средств для наличных денег;«доступность только для чтения» конкретной переменной определяется владельцем хранилища.Экземпляр ссылочного типа «владеет» своим собственным хранилищем, а экземпляр типа значения - нет!

struct S
{
  private readonly int x;
  public S(int x) { this.x = x; }
  public void Badness(ref S s)
  {
    Console.WriteLine(this.x);   
    s = new S(this.x + 1);
    // This should be the same, right?
    Console.WriteLine(this.x);   
  }
}

Кто-то думает, что this.x не изменится, потому что x это поле только для чтения, а Badness не является конструктором.Но ...

S s = new S(1);
s.Badness(ref s);

... ясно демонстрирует ложность этого.this и s относятся к одной и той же переменной, а , что переменная не доступна только для чтения!

49 голосов
/ 29 марта 2012

Нечистый метод - это метод, который не гарантирует, что значение останется таким, каким оно было.

В .NET 4 вы можете декорировать методы и типы с помощью [Pure], чтобы объявить ихбыть чистым, и R # примет это к сведению.К сожалению, вы не можете применить его к чужим членам и не можете убедить R # в том, что тип / член является чистым в проекте .NET 3.5, насколько мне известно.(Это кусает меня за время Ноды все время.)

Идея заключается в том, что если вы вызываете метод, который изменяет переменную, но вы вызываете егов поле только для чтения, вероятно, не делает то, что вы хотите, поэтому R # предупредит вас об этом.Например:

public struct Nasty
{
    public int value;

    public void SetValue()
    {
        value = 10;
    }
}

class Test
{
    static readonly Nasty first;
    static Nasty second;

    static void Main()
    {
        first.SetValue();
        second.SetValue();
        Console.WriteLine(first.value);  // 0
        Console.WriteLine(second.value); // 10
    }
}

Это было бы действительно полезным предупреждением, если бы каждый метод, который был действительно чистым, был объявлен таким образом.К сожалению, это не так, поэтому существует много ложных срабатываний: (* ​​1017 *

15 голосов
/ 29 марта 2012

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

Более длинный ответ заключается в том, что при доступе к типу значения только для чтения создается копия изэто так, что любые изменения значения, сделанные методом, будут влиять только на копию.ReSharper не понимает, что Contains - это чистый метод (то есть он не имеет побочных эффектов).Эрик Липперт говорит об этом здесь: Mutating Readonly Structs

11 голосов
/ 29 марта 2012

Похоже, что Reshaprer считает, что метод Contains может изменить значение rect.Поскольку rect является readonly struct, компилятор C # делает защитные копии значения, чтобы метод не изменял поле readonly.По сути, окончательный код выглядит следующим образом

Rectangle temp = rect;
if (temp.Contains(point)) {
  ...
}

Resharper предупреждает вас здесь, что Contains может видоизменить rect таким образом, что он будет немедленно потерян, потому что это произошло на временной основе.

5 голосов
/ 29 марта 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...