c# resharper preconditions

c# - Curiosidad de ReSharper: "El parámetro solo se utiliza para las comprobaciones previas".



preconditions (4)

Curiosamente, ReSharper retrocede si usa el nuevo nameof funcionalidad 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)); } }

¿Por qué ReSharper me está juzgando por este código?

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

El segundo método del parámetro "settingValue" de ValidateCorrespondingValueType aparece atenuado con el siguiente mensaje de ReSharper: "El parámetro ''settingValue'' solo se usa para verificaciones de precondición".


Lo siguiente soluciona el problema (en ReSharper 2016.1.1, VS2015), pero no estoy seguro de que resuelva el problema ''correcto''. En cualquier caso, muestra la ambigüedad en la mecánica de ReSharper con respecto a este tema:

Esto produce la advertencia:

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

Pero esto no:

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

Es interesante que el código equivalente (la inversión fue realizada por ReSharper: D) da resultados diferentes. Parece que la coincidencia de patrones simplemente no recoge la segunda versión.


Mi solución preferida para este problema es hacer que resharper piense que se usa el parámetro. Esto tiene una ventaja sobre el uso de un atributo como UsedImplicitly porque si alguna vez deja de usar ese parámetro, resharper comenzará a advertirle nuevamente. Si usa un atributo, resharper tampoco captará futuras advertencias reales.

Una manera fácil de hacer pensar a resharper que se usa el parámetro es reemplazando throw con un método. Entonces en lugar de ...

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

...usted escribe:

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

Esto se documenta por sí solo para futuros programadores, y Resharper deja de quejarse.

La implementación de ThrowPreconditionViolation es trivial:

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 método de extensión en Exception es la contaminación del espacio de nombres, pero está bastante contenido.


No está juzgando, está tratando de ayudar :)

Si ReSharper ve que un parámetro solo se usa como un control para lanzar una excepción, lo atenúa, lo que indica que en realidad no lo está utilizando para un trabajo "real". Es muy probable que esto sea un error: ¿por qué pasar un parámetro que no va a usar? Por lo general, indica que lo ha usado en una condición previa, pero luego se olvidó (o ya no necesita) usarlo en otra parte del código.

Dado que el método es un método de aserción (es decir, todo lo que hace es afirmar que es válido), puede suprimir el mensaje marcando ValidateCorrespondingValueType como un método de aserción, utilizando los atributos de anotación de ReSharper, específicamente el atributo [AssertionMethod] :

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