Argument Validation

Es ist gute Praxis alle Argumente zu validieren, bevor sie verwendet werden.


public static double Divide(double divident, double divisor)

{

    if (divisor <= 0)

        throw new ArgumentOutOfRangeException("divisor", "Divisor must be nonnegative.");

    return divident / divisor;

}

Würde in diesem Beispiel das Argument nicht geprüft, dann würde eine DivideByZeroException geworfen werden (was zugegebenermaßen in diesem Beispiel auch nicht ganz sinn frei wäre – aber ich denke der Gedanke dahinter ist klar).

Besonders bei Referenztypen ist es kritisch, da diese NULL sein können. Wird die Validierung vergessen, dann wird eine NullReferenceException geworfen. Deshalb gibt es in der Codeanalyse auch die Regel CA1062: Validate arguments of public methods.

Würde eine Methode so aussehen:


public void CallMethodUnvaildated(object obj, string s)

{

    string msg = obj.ToString() + s.TrimEnd('/');

    Console.WriteLine(msg);

}

Würde man eine NullReferenceException bekommen, wenn das Objekt NULL wäre. Außerdem muss man aufpassen, dass das System nicht in einen inkonsistenten Zustand kommt. Besser ist es so:


public void CallMethodVaildated(object obj, string s)

{

    if (obj == null)

        throw new ArgumentNullException("obj");

    if (s == null)

        throw new ArgumentNullException("s");

    string msg = obj.ToString() + s.TrimEnd('/');

    Console.WriteLine(msg);

}

Jetzt wird eine

ArgumentNullException

geworfen, die den Namen des Parameters enthält.

Nun besteht eine Anwendung aber aus vielen Schichten. Für das öffentliche Interface ist das relevant. Intern produzieren wir aber einen Haufen Code, der nichts bringt, da wir besser auf Clientseite sicherstellen, dass NULL erst gar nicht übergeben wird. Dieser Code macht die Funktionen schlechter lesbar und muss mit gewartet werden. Außerdem braucht jede Validierung auch einen eigenen Test, da sonst die Codeabdeckung in die Knie geht. Viel Arbeit also für nix…

Wenn die Methoden nur intern aufgerufen werden, dann ist es besser Sie als internal und nicht als public zu kennzeichnen. Ist der Code in einer anderen Assembly, dann kann das InternalVisibleToAttribute in der AssemblyInfo.cs verwendet werden:

[assembly:InternalsVisibleTo("AssemblyNameOhneDLL")]

Dieses Attribut ist übrigens auch für das Testen sehr hilfreich. Ist die Assembly signiert, dann muss die Gegen-Assembly auch signiert werden und das PublicToken angegeben werden (siehe http://wp.me/p3AlMw-M).

Ist es nicht möglich, die Methode mit internal zu markieren, dann kann u.U. die Meldung auch unterdrückt werden:


[SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", Justification = "Only called internally.")]

public void TrustedCallers(object obj, string s)

{

    string msg = obj.ToString() + s.TrimEnd('/');

    Console.WriteLine(msg);

}

Allerdings muss man darauf achten dabei keine Sicherheitslücken entstehen zu lassen.

  • In “wirklich” öffentlichen Methoden immer alle Argumente validieren.
  • Bei der Validierung eine ArgumentXXXException mit dem ParameterNamen werfen.
  • Interne Methoden nach Möglichkeit als internal markieren.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s