ReSharper Curiosity: „Parameter wird nur für Vorbedingungsprüfungen verwendet.“

102

Warum beurteilt mich ReSharper nach diesem 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);
        }
    }

Die zweite Methode Der Parameter "settingsValue" von ValidateCorrespondingValueType wird von ReSharper mit der folgenden Meldung abgeblendet: "Der Parameter 'settingsValue' wird nur für Vorbedingungsprüfungen verwendet."

Corpsekicker
quelle
Sie können die Deklaration und Zuordnung von exceptionMessagein den if-block verschieben :)
AakashM
Sie können dies auch in der folgenden Methode tun: expectedText + = ""; und es hört auf, sich zu beschweren, da Sie es in der Methode verwendet haben.
PHPGuru

Antworten:

104

Es urteilt nicht, es versucht zu helfen :)

Wenn ReSharper feststellt, dass ein Parameter nur als Prüfung zum Auslösen einer Ausnahme verwendet wird, wird er ausgegraut, was darauf hinweist, dass Sie ihn nicht für "echte" Arbeiten verwenden. Dies ist höchstwahrscheinlich ein Fehler. Warum sollten Sie einen Parameter übergeben, den Sie nicht verwenden werden? Es zeigt normalerweise an, dass Sie es in einer Vorbedingung verwendet haben, es dann aber vergessen haben (oder nicht mehr benötigen), es an einer anderen Stelle im Code zu verwenden.

Da es sich bei der Methode um eine Assertionsmethode handelt (das heißt, sie bestätigt lediglich, dass sie gültig ist), können Sie die Nachricht unterdrücken, indem Sie sie ValidateCorrespondingValueTypeals Assertionsmethode markieren und dabei die Anmerkungsattribute von ReSharper verwenden , insbesondere das [AssertionMethod]Attribut:

[AssertionMethod]
private void ValidateCorrespondingValueType(SupportedType supportedType, object settingValue)
{
  // …
}
bürgermatt
quelle
3
Es ist eine schöne Prüfung, aber in diesem Fall hat R # ein wenig überschritten, würden Sie nicht sagen? Die Prüfung auf settingValue‚s - Typ kann nicht möglich sein , pre - Bedingung, da die Sache , die es gegen geprüft hat wird , ist nicht bekannt , bis einige Arbeit innerhalb des Körpers des Verfahrens geschehen ist!
AakashM
6
Aus diesem Grund müssen Sie ReSharper mitteilen, dass es sich um eine Assertionsmethode handelt. Der einzige Punkt dieser Methode besteht darin, die Vorbedingungsprüfung für eine andere Methode durchzuführen. Es ist eine Behauptung, aber ReSharper kann das nur wissen, wenn Sie es mit sagen [AssertionMethod].
Citizenmatt
10
Am Ende habe ich nur den Schweregrad der Inspektion in "Nicht anzeigen" geändert. Dies ist eine weitere Option.
Reggaeguitar
61
Es könnte eine nützliche Funktion gewesen sein, wenn man die Inspektion "nur Vorbedingung" unabhängig von der regulären Inspektion nicht verwendeter Parameter deaktivieren könnte; Derzeit werden bei der Inspektion zwei Probleme mit unterschiedlichem Schweregrad verwechselt, und diese Funktionalität wird in bestimmten Situationen im Allgemeinen unbrauchbar. Ich bin auch sehr skeptisch gegenüber der Idee, dem Code Kommentare oder Attribute hinzuzufügen, um ein Quellcode-Analysetool zufrieden zu stellen. Daher glaube ich im Moment nicht, dass es eine zufriedenstellende Lösung für das Problem gibt.
Serge Belov
7
Es könnte versuchen zu helfen, aber es ist zu aggressiv. Wenn Sie den Wert überprüfen und ihn dann nie verwenden, ist das wahrscheinlich ein Fehler. Es kläfft mich jedoch über einen, bei dem ich nur den Wert im Fehler verwende. Wie sonst kann das alles andere als beabsichtigt sein?
Loren Pechtel
20

Interessanterweise zieht sich ReSharper zurück, wenn Sie die neue nameofFunktionalität in C # 6 verwenden:

static void CheckForNullParameters(IExecutor executor, ILogger logger)
{
    if (executor == null)
    {
        throw new ArgumentNullException(nameof(executor));
    }

    if (logger == null)
    {
        throw new ArgumentNullException(nameof(logger));
    }
}
Holf
quelle
3
Diese Antwort passt zu mir, sie ist weniger aufdringlich als das Hinzufügen eines Nuget-Pakets
DanielV
8

Das Folgende behebt das Problem (in ReSharper 2016.1.1, VS2015), aber ich bin nicht sicher, ob es das "richtige" Problem löst. In jedem Fall zeigt es die Mehrdeutigkeit in der Mechanik von ReSharper in Bezug auf dieses Thema:

Dies ergibt die Warnung:

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

Das geht aber nicht:

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

Es ist interessant, dass äquivalenter Code (die Inversion wurde von ReSharper: D durchgeführt) unterschiedliche Ergebnisse liefert. Es scheint, dass der Mustervergleich die zweite Version einfach nicht aufgreift.

Maryn
quelle
6

Meine bevorzugte Lösung für dieses Problem ist make ReSharper denken , der Parameter wird verwendet. Dies hat einen Vorteil gegenüber der Verwendung eines Attributs, z. B. UsedImplicitlywenn Sie diesen Parameter nicht mehr verwenden, wird resharper Sie erneut warnen. Wenn Sie ein Attribut verwenden, fängt resharper auch zukünftige echte Warnungen nicht ab.

Eine einfache Möglichkeit, Resharper glauben zu lassen, dass der Parameter verwendet wird, besteht darin, ihn durch throweine Methode zu ersetzen . Also statt ...

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

...du schreibst:

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

Dies ist für zukünftige Programmierer eine gute Selbstdokumentation, und Resharper hört auf zu jammern.

Die Implementierung von ThrowPreconditionViolation ist 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;
    }
}

Eine Erweiterungsmethode für Ausnahmen ist die Verschmutzung von Namespaces, die jedoch ziemlich begrenzt ist.

Eamon Nerbonne
quelle
+1 zum Erwähnen [UsedImplicitly], ich wollte nicht verwenden, [AssertionMethod]wie es nicht war, und verwendet klingt implizit genauer in meinem Fall (ich habe einen Wert an einen Rückruf in einem Konstruktor übergeben und das konstruierte Objekt zurückgegeben).
MrLore
1

Andere haben die Frage bereits beantwortet, aber niemand erwähnte die folgenden Möglichkeiten, die Warnung auszuschalten.

Fügen Sie dies über der Methodensignatur hinzu, um es nur für diese Methode zu deaktivieren:

    // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local

Fügen Sie dies über der Klassendeklaration hinzu, um es für die gesamte Datei zu deaktivieren:

     // ReSharper disable ParameterOnlyUsedForPreconditionCheck.Local
todji
quelle
Ein Nachteil ist, dass Sie keinen Hexenparameter angeben können, den Sie meinen.
Comecme
1
@comecme Sie können für einen einzelnen Parameter deaktivieren, indem Sie Kommentare zu diesem bestimmten Parameter deaktivieren und wiederherstellen . Ich würde vorschlagen, in diesem Fall jeden Parameter in eine eigene Zeile zu setzen. immer noch hässlich, aber weniger (meiner Meinung nach).
Travis