ReSharper Curiosity: "Le paramètre n'est utilisé que pour le (s) contrôle (s) des conditions préalables."

102

Pourquoi ReSharper me juge pour ce code?

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

Le paramètre "settingValue" de la deuxième méthode ValidateCorrespondingValueType est grisé avec le message suivant de ReSharper: "Le paramètre" settingValue "est uniquement utilisé pour les vérifications de précondition."

Corpsekicker
la source
Vous pouvez déplacer la déclaration et l'assignation de exceptionMessagedans le ifbloc :)
AakashM
Vous pouvez également le faire dans la méthode: expectedText + = ""; et il cesse de se plaindre puisque vous l'avez utilisé dans la méthode.
PHPGuru

Réponses:

104

Ce n'est pas de juger, c'est d'essayer d'aider :)

Si ReSharper voit qu'un paramètre n'est utilisé que comme contrôle pour lever une exception, il le grise, indiquant que vous ne l'utilisez pas réellement pour un travail "réel". C'est probablement une erreur - pourquoi passer un paramètre que vous n'allez pas utiliser? Cela indique généralement que vous l'avez utilisé dans une condition préalable, mais que vous avez ensuite oublié (ou n'avez plus besoin) de l'utiliser ailleurs dans le code.

Étant donné que la méthode est une méthode d'assertion (c'est-à-dire qu'elle ne fait qu'affirmer qu'elle est valide), vous pouvez supprimer le message en marquant ValidateCorrespondingValueTypecomme méthode d'assertion, en utilisant les attributs d'annotation de ReSharper , en particulier l' [AssertionMethod]attribut:

[AssertionMethod]
private void ValidateCorrespondingValueType(SupportedType supportedType, object settingValue)
{
  // …
}
citizenmatt
la source
3
C'est un bon chèque, mais dans ce cas, R # a dépassé un peu, n'est-ce pas? Le type de vérification settingValuene peut pas être une condition préalable, car la chose contre laquelle il est vérifié n'est pas connue tant que du travail n'a pas été effectué dans le corps de la méthode!
AakashM
6
C'est pourquoi vous devez dire à ReSharper qu'il s'agit d'une méthode d'assertion. Le seul point de cette méthode est d'effectuer le contrôle de pré-condition pour une autre méthode. C'est une affirmation, mais ReSharper ne peut pas le savoir à moins que vous ne le disiez avec [AssertionMethod].
citizenmatt
10
J'ai fini par changer simplement la gravité de l'inspection en "Ne pas afficher", c'est une autre option.
reggaeguitar
61
Cela aurait pu être une fonctionnalité utile, si l'on pouvait désactiver l'inspection «pré-condition seulement» indépendamment de l'inspection régulière des paramètres inutilisés; dans l'état actuel des choses, l'inspection mélange deux problèmes de gravité différente et rend généralement cette fonctionnalité inutile dans certaines situations. Je suis également très sceptique quant à l'idée d'ajouter des commentaires ou des attributs au code juste pour garder un outil d'analyse de code source heureux, donc pour le moment, je ne pense pas qu'il existe une solution satisfaisante au problème.
Serge Belov
7
Il essaie peut-être d'aider mais c'est trop agressif. Maintenant, si vous vérifiez la valeur et que vous ne l'utilisez jamais, très bien, c'est probablement une erreur. Cependant, il me jette dessus sur un où je n'utilise que la valeur de l'erreur. Sinon, comment cela peut-il être autre chose qu'intentionnel?
Loren Pechtel
20

Fait intéressant, ReSharper recule si vous utilisez la nouvelle nameoffonctionnalité en 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
la source
3
cette réponse me convient, elle est moins intrusive que l'ajout d'un paquet
nuget
8

Ce qui suit résout le problème (dans ReSharper 2016.1.1, VS2015), mais je ne suis pas sûr que cela résout le «bon» problème. Dans tous les cas, cela montre l'ambiguïté dans la mécanique de ReSharper concernant ce sujet:

Cela donne l'avertissement:

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

Mais cela ne fait pas:

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

Il est intéressant de noter qu'un code équivalent (l'inversion a été faite par ReSharper: D) donne des résultats différents. Il semble que la correspondance de motifs ne reprend tout simplement pas la deuxième version.

Maryn
la source
6

Ma solution préférée à ce problème est de faire en sorte que resharper pense que le paramètre est utilisé. Cela a un avantage par rapport à l' aide d' un attribut tel que UsedImplicitlyparce que si jamais vous ne en utilisant ce paramètre arrêt, ReSharper commencera à vous avertir à nouveau. Si vous utilisez un attribut, le resharper ne captera pas non plus les futurs avertissements réels.

Un moyen simple de faire en sorte que resharper pense que le paramètre est utilisé consiste à le remplacer throwpar une méthode. Alors au lieu de ...

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

...vous écrivez:

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

Ceci est bien auto-documenté pour les futurs programmeurs, et le resharper arrête de pleurnicher.

L'implémentation de ThrowPreconditionViolation est triviale:

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

Une méthode d'extension sur Exception est la pollution de l'espace de noms, mais elle est assez contenue.

Eamon Nerbonne
la source
+1 pour mentionner [UsedImplicitly], je ne voulais pas utiliser [AssertionMethod]car il ne l'était pas, et utilisé implicitement semble plus précis dans mon cas (je passais une valeur à un rappel dans un constructeur et retournais l'objet construit).
MrLore
1

D'autres ont déjà répondu à la question, mais personne n'a mentionné les façons suivantes de désactiver l'avertissement.

Ajoutez ceci au-dessus de la signature de la méthode pour la désactiver uniquement pour cette méthode:

    // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local

Ajoutez ceci au-dessus de la déclaration de classe pour la désactiver pour tout le fichier:

     // ReSharper disable ParameterOnlyUsedForPreconditionCheck.Local
Todji
la source
Un inconvénient est que vous ne pouvez pas spécifier le paramètre de sorcière que vous voulez dire.
comecme le
1
@comecme Vous pouvez désactiver pour un seul paramètre en utilisant désactiver et restaurer les commentaires autour de ce paramètre particulier. Je suggère de mettre chaque paramètre sur sa propre ligne dans ce cas; toujours moche mais moins (à mon avis).
Travis