Цікавість ReSharper: "Параметр використовується лише для перевірки передумов."


102

Чому 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);
        }
    }

Другий метод ValidateCorrespondingValueType параметр "settingValue" виділяється сірим кольором із наступним повідомленням ReSharper: "Параметр 'settingsValue' використовується лише для перевірки (-ів) попередніх умов."


Ви можете перемістити декларацію та призначення exceptionMessageв if-бло :)
AakashM

Ви також можете це зробити методом: очакванийТекст + = ""; і він перестає скаржитися, оскільки ви використовували його в методі.
PHPGuru

Відповіді:


104

Це не судити, намагається допомогти :)

Якщо ReSharper бачить, що параметр використовується лише як перевірка для викидання винятку, він відображає його, вказуючи, що ви насправді не використовуєте його для "реальної" роботи. Це, швидше за все, помилка - чому передати параметр, який ви не збираєтеся використовувати? Зазвичай це означає, що ви використовували його в попередній умові, але потім забули (або більше не потрібно) використовувати його в іншому місці коду.

Оскільки метод є методом твердження (тобто все, що він робить, це стверджує, що він дійсний), ви можете придушити повідомлення, позначивши ValidateCorrespondingValueTypeяк метод ствердження, використовуючи анотації анотації ReSharper , зокрема [AssertionMethod]атрибут:

[AssertionMethod]
private void ValidateCorrespondingValueType(SupportedType supportedType, object settingValue)
{
  // …
}

3
Це гарна перевірка, але в цьому випадку R # трохи перевищив, чи не сказати б ви? Перевірка settingValueтипу 's не може бути попередньою умовою, оскільки те, на що він перевіряється, не відоме, поки не буде виконана якась робота в тілі методу!
AakashM

6
Ось чому потрібно сказати ReSharper, що це метод твердження. Єдиним моментом цього методу є проведення передумови перевірки іншого методу. Це твердження, але ReSharper не може цього знати, якщо ви не скажете це [AssertionMethod].
Citizenmatt

10
У кінцевому підсумку я просто змінив рівень інспекції на "Не показувати", це ще один варіант.
reggaeguitar

61
Це може бути корисною функцією, якби можна було відключити перевірку "лише умова" незалежно від звичайної перевірки невикористаних параметрів; на даний момент інспекція поєднує два питання різного ступеня тяжкості і, як правило, робить цю функцію марною в певних ситуаціях. Я також дуже скептично ставлюсь до ідеї додавання коментарів або атрибутів до коду, щоб задовольнити інструмент аналізу вихідного коду, тому на даний момент я не думаю, що питання є задовільним.
Серж Бєлов

7
Це може намагатися допомогти, але це занадто агресивно. Тепер, якщо ви перевіряєте значення, а потім ніколи не використовуєте його, добре, це, швидше за все, помилка. Однак, це натягує на мене один, де я використовую лише значення помилки. Як інакше це може бути не що інше, як навмисне?
Лорен Печтел

20

Цікаво, що 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));
    }
}

3
ця відповідь мене влаштовує, вона менш нав'язлива, ніж додавання нужного пакету
DanielV

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 також не вловлює майбутні реальні попередження.

Найпростіший спосіб зробити переосмислення думки, що параметр використовується шляхом заміни throwметодом. Тож замість ...

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

...Ви пишете:

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

Це приємно самостійно документувати майбутніх програмістів, і переосмислення кидає скигнути.

Реалізація 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

Недоліком є ​​те, що ви не можете вказати вказаний вами параметр.
comecme

1
@comecme Ви можете відключити один параметр за допомогою відключення та відновлення коментарів навколо цього конкретного параметра. Я б запропонував у цьому випадку кожен параметр поставити у свій рядок; все ще негарна, але менш (на мій погляд).
Тревіс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.