ReSharper Curiosity: "Il parametro viene utilizzato solo per i controlli delle precondizioni."


102

Perché ReSharper mi giudica per questo codice?

    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);
        }
    }

Il parametro "settingValue" del secondo metodo ValidateCorrespondingValueType è disattivato con il seguente messaggio di ReSharper: "Il parametro 'settingValue' viene utilizzato solo per i controlli delle precondizioni."


Puoi spostare la dichiarazione e l'assegnazione di exceptionMessagenel ifblocco :)
AakashM

Puoi farlo anche nel metodo: expectedText + = ""; e smette di lamentarsi da quando l'hai usato nel metodo.
PHPGuru

Risposte:


104

Non sta giudicando, sta cercando di aiutare :)

Se ReSharper vede che un parametro viene utilizzato solo come controllo per generare un'eccezione, lo rende grigio, indicando che non lo stai effettivamente utilizzando per un lavoro "reale". Questo è molto probabilmente un errore: perché passare un parametro che non utilizzerai? Di solito indica che l'hai usato in una pre-condizione, ma poi hai dimenticato (o non hai più bisogno) di usarlo altrove nel codice.

Poiché il metodo è un metodo di asserzione (ovvero, tutto ciò che fa è asserire che è valido), puoi sopprimere il messaggio contrassegnando ValidateCorrespondingValueTypecome metodo di asserzione, utilizzando gli attributi di annotazione di ReSharper , in particolare l' [AssertionMethod]attributo:

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

3
È un bel controllo, ma in questo caso R # ha superato un po ', non credi? Il tipo di controllo settingValuenon può essere una precondizione , poiché la cosa su cui si sta controllando non è nota finché non è stato fatto del lavoro all'interno del corpo del metodo!
AakashM

6
Ecco perché devi dire a ReSharper che è un metodo di asserzione. L'unico punto di questo metodo è eseguire il controllo delle precondizioni per un altro metodo. È un'affermazione, ma ReSharper non può saperlo a meno che tu non lo dica con [AssertionMethod].
citizenmatt

10
Ho finito per cambiare la gravità dell'ispezione in "Non mostrare", questa è un'altra opzione.
reggaeguitar

61
Potrebbe essere stata una caratteristica utile, se si potesse disabilitare l'ispezione "solo pre-condizione" indipendentemente dalla regolare ispezione dei parametri inutilizzati; così com'è, l'ispezione confonde due problemi di diversa gravità e generalmente rende questa funzionalità inutile in determinate situazioni. Sono anche molto scettico sull'idea di aggiungere commenti o attributi al codice solo per mantenere felice uno strumento di analisi del codice sorgente, quindi al momento non penso che ci sia una soluzione soddisfacente al problema.
Serge Belov

7
Potrebbe cercare di aiutare, ma è troppo aggressivo. Ora, se verifichi il valore e poi non lo usi mai, va bene, è probabile che sia un errore. Tuttavia, mi sta abbaiando su uno in cui uso solo il valore nell'errore. In quale altro modo può essere tutt'altro che intenzionale?
Loren Pechtel

20

È interessante notare che ReSharper si arresta se si utilizza la nuova nameoffunzionalità in 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
questa risposta mi si addice, è meno invadente rispetto all'aggiunta di un pacchetto
nuget

8

Quanto segue risolve il problema (in ReSharper 2016.1.1, VS2015), ma non sono sicuro che risolva il problema "corretto". In ogni caso, mostra l'ambiguità nelle meccaniche di ReSharper riguardo a questo argomento:

Questo produce l'avvertimento:

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

Ma questo non:

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

È interessante che il codice equivalente (l'inversione è stata fatta da ReSharper: D) dia risultati diversi. Sembra che il pattern matching semplicemente non riprenda la seconda versione.


6

La mia soluzione preferita a questo problema è fare in modo che resharper pensi che il parametro sia utilizzato. Questo ha un vantaggio rispetto all'utilizzo di un attributo come UsedImplicitlyperché se mai lo fai smettere di usare quel parametro, ReSharper inizierà avvertendo di nuovo. Se utilizzi un attributo, resharper non rileverà nemmeno i futuri avvisi reali.

Un modo semplice per far credere a resharper che il parametro sia utilizzato è sostituirlo throwcon un metodo. Quindi invece di ...

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

...Scrivi:

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

Questo è abbastanza auto-documentante per i futuri programmatori e resharper smette di lamentarsi.

L'implementazione di ThrowPreconditionViolation è banale:

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;
    }
}

Un metodo di estensione su Exception è l' inquinamento dello spazio dei nomi, ma è abbastanza contenuto.


+1 per la menzione [UsedImplicitly], non volevo usare in [AssertionMethod]quanto non lo era, e usato implicitamente suona più accurato nel mio caso (stavo passando un valore a un callback in un costruttore e restituivo l'oggetto costruito).
MrLore

1

Altri hanno già risposto alla domanda, ma nessuno ha menzionato i seguenti modi per disattivare l'avviso.

Aggiungi questo sopra la firma del metodo per disattivarlo solo per quel metodo:

    // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local

Aggiungi questo sopra la dichiarazione della classe per disattivarlo per l'intero file:

     // ReSharper disable ParameterOnlyUsedForPreconditionCheck.Local

Uno svantaggio è che non puoi specificare il parametro della strega che intendi.
arrivo il

1
@comecme È possibile disabilitare per un singolo parametro utilizzando disabilita e ripristina i commenti attorno a quel particolare parametro. Suggerirei di mettere ogni parametro sulla propria riga in questo caso; ancora brutta ma meno (secondo me).
Travis
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.