ReSharper Curiosity: "Parameter is only used for precondition check(s)."

24.7k views Asked by At

Why is ReSharper judging me for this 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);
        }
    }

The second method ValidateCorrespondingValueType's "settingValue" parameter is grayed out with the following message by ReSharper: "Parameter 'settingValue' is only used for precondition check(s)."

7

There are 7 answers

14
citizenmatt On BEST ANSWER

It's not judging, it's trying to help :)

If ReSharper sees that a parameter is only used as a check to throw an exception, it greys it out, indicating that you're not actually using it for "real" work. This is most likely a mistake - why pass in a parameter you're not going to use? It usually indicates that you've used it in a pre-condition, but then forgotten (or no longer need) to use it elsewhere in the code.

Since the method is an assertion method (that is, all it does is assert it's valid), you can suppress the message by marking the ValidateCorrespondingValueType as an assertion method, using ReSharper's annotation attributes, specifically the [AssertionMethod] attribute:

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

My preferred solution to this problem is make resharper think the parameter is used. This has an advantage over using an attribute such as UsedImplicitly because if ever you do stop using that parameter, resharper will start warning you again. If you use an attribute, resharper won't catch future real warnings either.

An easy way to make resharper think the paramter is used is by replacing throw with a method. So instead of...

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

...you write:

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

This is nicely self-documenting for future programmers, and resharper quits whining.

The implementation of ThrowPreconditionViolation is 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;
    }
}

An extension method on Exception is namespace pollution, but it's fairly contained.

0
mkb On

I believe below is a legit case where I check all items in list with lambda Any method. Then I use the same way the next line but resharper fails.

if (actions.Any(t => t.Id == null)) // here says Paramter t is used only for precondition check(s)
    throw new Exception();
actionIds = actions.Select(t => t.Id ?? 0).ToList();

I had to ignore with comment.

2
todji On

Others have already answered the question, but no one mentioned the following ways of turning off the warning.

Add this above the method signature to turn it off for only that method:

    // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local

Add this above the class declaration to turn it off for the entire file:

     // ReSharper disable ParameterOnlyUsedForPreconditionCheck.Local
0
Michael Snytko On

use this comment above parameter

// ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local

to disable suggestion in Rider

0
AudioBubble On

The following fixes the issue (in ReSharper 2016.1.1, VS2015), but I am not sure it solves the 'right' problem. In any case, it shows the ambiguity in ReSharper's mechanics regarding this topic:

This yields the warning:

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

But this does not:

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

It is interesting that equivalent code (the inversion was done by ReSharper :D) gives different results. It seems that the pattern matching simply does not pick up the second version.

1
Holf On

Interestingly, ReSharper backs off if you use the new nameof functionality 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));
    }
}