ReSharper Curiosity: «Параметр используется только для проверки предварительных условий».

103

Почему ReSharper судит меня за этот код?

    private Control GetCorrespondingInputControl(SupportedType supportedType, object settingValue)
    {
        this.ValidateCorrespondingValueType(supportedType, settingValue);

        switch(supportedType)
        {
            case SupportedType.String:
                return new TextBox { Text = (string)settingValue };
            case SupportedType.DateTime:
                return new MonthPicker { Value = (DateTime)settingValue, ShowUpDown = true };
            default:
                throw new ArgumentOutOfRangeException(string.Format("The supported type value, {0} has no corresponding user control defined.", supportedType));
        }
    }

    private void ValidateCorrespondingValueType(SupportedType supportedType, object settingValue)
    {
        Type type;

        switch(supportedType)
        {
            case SupportedType.String:
                type = typeof(string);
                break;
            case SupportedType.DateTime:
                type = typeof(DateTime);
                break;
            default:
                throw new ArgumentOutOfRangeException(string.Format("The supported type value, {0} has no corresponding Type defined.", supportedType));
        }
        string exceptionMessage = string.Format("The specified setting value is not assignable to the supported type, [{0}].", supportedType);
        if(settingValue.GetType() != type)
        {
            throw new InvalidOperationException(exceptionMessage);
        }
    }

Параметр "settingValue" второго метода ValidateCorrespondingValueType отображается серым цветом со следующим сообщением от ReSharper: "Параметр 'settingValue' используется только для проверки предварительных условий".

Труп
источник
Вы можете переместить объявление и присвоение exceptionMessageв if
-блок
Вы также можете сделать это в методе: expectedText + = ""; и он перестает жаловаться, поскольку вы использовали его в методе.
PHPGuru

Ответы:

104

Это не осуждает, а пытается помочь :)

Если ReSharper видит, что параметр используется только для проверки исключения, он выделяет его серым цветом, указывая на то, что вы на самом деле не используете его для «реальной» работы. Скорее всего, это ошибка - зачем передавать параметр, который вы не собираетесь использовать? Обычно это означает, что вы использовали его в предварительном условии, но затем забыли (или больше не нуждаетесь) в его использовании в другом месте кода.

Поскольку метод является методом утверждения (то есть все, что он делает, это утверждает, что он действителен), вы можете подавить сообщение, пометив ValidateCorrespondingValueTypeкак метод утверждения, используя атрибуты аннотации ReSharper , в частности [AssertionMethod]атрибут:

[AssertionMethod]
private void ValidateCorrespondingValueType(SupportedType supportedType, object settingValue)
{
  // …
}
гражданин
источник
3
Хорошая проверка, но в данном случае R # немного перевалил, не так ли? Проверка settingValueтипа не может быть предварительным условием, так как объект проверки неизвестен до тех пор, пока не будет выполнена некоторая работа в теле метода!
AakashM
6
Вот почему вам нужно сообщить ReSharper, что это метод утверждения. Единственная цель этого метода - выполнить предварительную проверку для другого метода. Это утверждение, но ReSharper не может этого узнать, пока вы не сообщите об этом с помощью [AssertionMethod].
Citizenmatt
10
В итоге я просто изменил серьезность проверки на «Не показывать», это еще один вариант.
регги-гитара
61
Это могло бы быть полезной функцией, если бы можно было отключить проверку «только предварительных условий» независимо от регулярной проверки неиспользуемых параметров; в его нынешнем виде проверка смешивает две проблемы разной степени серьезности и, как правило, делает эту функциональность бесполезной в определенных ситуациях. Я также очень скептически отношусь к идее добавления комментариев или атрибутов к коду только для того, чтобы инструмент анализа исходного кода был доволен, поэтому на данный момент я не думаю, что есть удовлетворительное решение проблемы.
Серж Белов
7
Может, он пытается помочь, но слишком агрессивен. Теперь, если вы проверите значение, а затем никогда не используете его, хорошо, вероятно, это ошибка. Однако он тявкает на меня из-за того, что я использую только значение ошибки. Как еще это может быть не преднамеренным?
Лорен Пехтель,
21

Интересно, что ReSharper отступает, если вы используете новую nameofфункциональность в C # 6:

static void CheckForNullParameters(IExecutor executor, ILogger logger)
{
    if (executor == null)
    {
        throw new ArgumentNullException(nameof(executor));
    }

    if (logger == null)
    {
        throw new ArgumentNullException(nameof(logger));
    }
}
Holf
источник
3
этот ответ меня устраивает, он менее навязчив, чем добавление пакета
nuget
8

Следующее устраняет проблему (в ReSharper 2016.1.1, VS2015), но я не уверен, что это решает «правильную» проблему. В любом случае, это показывает неоднозначность механики ReSharper по этой теме:

Это дает предупреждение:

    private void CheckForNull(object obj)
    {
        if (ReferenceEquals(obj, null))
        {
            throw new Exception();
        }
    }

Но это не так:

    private void CheckForNull(object obj)
    {
        if (!ReferenceEquals(obj, null))
        {
            return;
        }
        throw new Exception();
    }

Интересно, что эквивалентный код (инверсия была сделана ReSharper: D) дает разные результаты. Кажется, что сопоставление с образцом просто не подхватывает вторую версию.

Мэрин
источник
6

Мое предпочтительное решением этой проблемы является маркой ReSharper думает параметр будет использоваться. Это имеет преимущество по сравнению с использованием атрибута , такого как , UsedImplicitlyпотому что , если бы вы действительно остановить с помощью этого параметра, ReSharper снова начнет вас предупреждаю. Если вы используете атрибут, resharper также не будет ловить настоящие предупреждения в будущем.

Простой способ заставить resharper подумать, что параметр используется, - это заменить throwего методом. Так что вместо ...

if(myPreconditionParam == wrong)
    throw new Exception(...);

...ты пишешь:

if(myPreconditionParam == wrong)
    new Exception(...).ThrowPreconditionViolation();

Это приятно самодокументируется для будущих программистов, и resharper перестает ныть.

Реализация ThrowPreconditionViolation тривиальна:

public static class WorkAroundResharperBugs 
{
    //NOT [Pure] so resharper shuts up; the aim of this method is to make resharper 
    //shut up about "Parameter 'Foobaar' is used only for precondition checks" 
    //optionally: [DebuggerHidden]
    public static void ThrowPreconditionViolation(this Exception e)
    {
        throw e;
    }
}

Метод расширения Exception - это загрязнение пространства имен, но оно достаточно ограничено.

Эамон Нербонн
источник
+1 для упоминания [UsedImplicitly], я не хотел использовать, [AssertionMethod]поскольку его не было, и используется неявно звучит более точно в моем случае (я передавал значение обратному вызову в конструкторе и возвращал созданный объект).
MrLore
1

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

Добавьте это выше сигнатуры метода, чтобы отключить его только для этого метода:

    // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local

Добавьте это над объявлением класса, чтобы отключить его для всего файла:

     // ReSharper disable ParameterOnlyUsedForPreconditionCheck.Local
тоджи
источник
Недостатком является то, что вы не можете указать параметр, который имеете в виду.
приходите
1
@comecme Вы можете отключить для одного параметра, используя отключить и восстановить комментарии вокруг этого конкретного параметра. В этом случае я бы посоветовал поместить каждый параметр в отдельную строку; все еще некрасиво, но в меньшей степени (на мой взгляд).
Трэвис