Pourquoi ReSharper me juge-t-il 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);
}
}
La deuxième méthode du paramètre "settingValue" de ValidateCorrespondingValueType est grisée avec le message suivant par ReSharper: "Le paramètre 'settingValue' n'est utilisé que pour les vérifications de précondition."
Ce n'est pas juger, c'est essayer d'aider :)
Si ReSharper voit qu'un paramètre n'est utilisé que comme vérification pour lever une exception, il le grise, indiquant que vous ne l'utilisez pas réellement pour un "vrai" travail. 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 que vous n'avez plus besoin) de l'utiliser ailleurs dans le code.
Puisque 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 ValidateCorrespondingValueType
comme méthode d'assertion, en utilisant ReSharper les attributs d'annotation , en particulier le [AssertionMethod]
attribut:
[AssertionMethod]
private void ValidateCorrespondingValueType(SupportedType supportedType, object settingValue)
{
// …
}
Fait intéressant, ReSharper se retire si vous utilisez la nouvelle fonctionnalité nameof
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));
}
}
Ma solution préférée à ce problème est de faire penser à resharper le paramètre is utilisé. Cela présente un avantage sur l'utilisation d'un attribut tel que UsedImplicitly
car si jamais vous do arrêtez d'utiliser ce paramètre, resharper recommencera à vous avertir. Si vous utilisez un attribut, resharper n'attrapera pas non plus les vrais avertissements futurs.
Un moyen simple de faire croire à resharper que le paramètre est utilisé est de remplacer throw
par une méthode. Donc 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 cesse 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 is pollution de l'espace de noms, mais elle est assez contenue.
Ce qui suit résout le problème (dans ReSharper 2016.1.1, VS2015), mais je ne suis pas sûr qu'il 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 signifie pas:
private void CheckForNull(object obj)
{
if (!ReferenceEquals(obj, null))
{
return;
}
throw new Exception();
}
Il est intéressant de noter que le code équivalent (l'inversion a été effectuée 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.