Я использую Visual Studio 2010 + Resharper, и он показывает предупреждение о следующем коде:
if (rect.Contains(point))
{
...
}
rect
- это readonly Rectangle
поле, и Resharper показывает мне это предупреждение:
«Нечистый метод вызывается для поля типа значения только для чтения».
Что такое нечистые методы и почему мне показывают это предупреждение?
Ответы:
Во-первых, ответы Джона, Майкла и Джареда в основном верны, но я хотел бы добавить к ним еще несколько вещей.
Чистые методы охарактеризовать проще. «Чистый» метод имеет следующие характеристики:
Например,
Math.Cos
это чистый метод. Его вывод зависит только от его ввода, и ввод не изменяется при вызове.Нечистый метод - это не чистый метод.
На ум приходят два. На первый указал Джон, Майкл и Джаред, и именно об этом вас предупреждает Решарпер. Когда вы вызываете метод в структуре, мы всегда передаем ссылку на переменную, которая является получателем, на случай, если метод желает изменить переменную.
Так что, если вы вызовете такой метод для значения, а не для переменной? В этом случае мы создаем временную переменную, копируем в нее значение и передаем ссылку на переменную.
Переменная только для чтения считается значением, потому что ее нельзя изменить вне конструктора. Итак, мы копируем переменную в другую переменную, и нечистый метод, возможно, изменяет копию, когда вы намереваетесь изменить переменную.
Это опасность передачи структуры только для чтения в качестве получателя . Также существует опасность передачи структуры, содержащей поле только для чтения. Структура, содержащая поле только для чтения, является обычной практикой, но по сути это проверка того, что у системы типов нет средств для обналичивания; «Доступность только для чтения» конкретной переменной определяется владельцем хранилища. Экземпляр ссылочного типа «владеет» своим собственным хранилищем, а экземпляр типа значения - нет!
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
относятся к той же переменной, и эта переменная не доступна только для чтения!источник
struct Id {
private readonly int _id;
public Id(int id) { _id = id; }
public int ToInt() => _id;
}
Почему ToInt нечист?return
. Исходя из этого, я предполагаю, что единственным критерием является наличие у метода[Pure]
атрибута.rect
. Мы говорим, что копияrect
передаетсяContains
методу?Нечистый метод - это метод, который не гарантирует сохранение значения как было.
В .NET 4 вы можете декорировать методы и типы,
[Pure]
чтобы объявить их чистыми, и R # это заметит. К сожалению, вы не можете применить его к другим членам, и вы не можете убедить R #, что тип / член является чистым в проекте .NET 3.5, насколько мне известно. (Это все время кусает меня в Noda Time .)Идея в том , что если вы вызываете метод , который мутирует переменной, но вы вызываете его на поле только для чтения, это, вероятно , не делать то , что вы хотите, так что 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 } }
Это было бы действительно полезным предупреждением, если бы каждый метод, который на самом деле был чистым, был объявлен таким образом. К сожалению, это не так, поэтому ложных срабатываний много :(
источник
JetBrains.Annotations.PureAttribute
вместо нихSystem.Diagnostics.Contracts.PureAttribute
, они имеют то же значение для анализа кода ReSharper и должны одинаково работать в .NET 3.5, .NET 4 или Silverlight. Вы также можете добавлять внешние аннотации к сборкам, которыми вы не владеете, с помощью файлов XML (посмотрите каталог ExternalAnnotations в пути к корзине ReSharper), это действительно может быть очень полезно!System.Diagnostics.Contracts.PureAttribute
это предупреждение не подавлялось в R # 8.2, а подавлялосьJetBrains.Annotations.PureAttribute
. Эти два атрибута также имеют разные описания:Pure
атрибут контрактов подразумевает «результат зависит только от параметров», тогда как JetBrainsPure
подразумевает «не вызывает видимых изменений состояния», не исключая состояния объекта, используемого для вычисления результата. (Но все же контракты,Pure
не оказывающие такого же эффекта на это предупреждение, вероятно, являются ошибкой.)Короткий ответ: это ложное срабатывание, и вы можете игнорировать предупреждение.
Более длинный ответ заключается в том, что доступ к типу значения, доступному только для чтения, создает его копию , так что любые изменения значения, внесенные методом, будут влиять только на копию. ReSharper не понимает, что
Contains
это чистый метод (то есть у него нет побочных эффектов). Эрик Липперт говорит об этом здесь: Мутация структур, доступных только для чтенияисточник
private readonly SpinLock _spinLock = new SpinLock();
- такая блокировка была бы совершенно бесполезной (поскольку модификатор readonly вызывает создание копии на лету каждый раз, когда для нее вызывается метод Enter)Похоже, Решапрер считает, что метод
Contains
может изменятьrect
значение. Посколькуrect
этоreadonly struct
компилятор C # создает защитные копии значения, чтобы предотвратить изменениеreadonly
поля методом . По сути, окончательный код выглядит такRectangle temp = rect; if (temp.Contains(point)) { ... }
Resharper предупреждает вас здесь, что
Contains
может изменитьсяrect
так, что будет немедленно потеряно, потому что это произошло временно.источник
Нечистый метод - это метод, который может иметь побочные эффекты. В этом случае Resharper, кажется, думает, что это может измениться
rect
. Вероятно, нет, но цепочка доказательств прервана.источник