411 Stimmen

Was passiert in C#, wenn Sie eine Erweiterungsmethode für ein Null-Objekt aufrufen?

Wird die Methode mit einem Nullwert aufgerufen oder wird eine Nullreferenz-Ausnahme ausgelöst?

MyObject myObject = null;
myObject.MyExtensionMethod(); // <-- is this a null reference exception?

Wenn dies der Fall ist, werde ich nie brauchen, um meine "this"-Parameter für null überprüfen?

475voto

Marc Gravell Punkte 970173

Das funktioniert (ohne Ausnahme). Erweiterungsmethoden verwenden keine virtuellen Aufrufe (d.h. sie verwenden die Anweisung "call" il, nicht "callvirt"), so dass es keine Nullprüfung gibt, es sei denn, Sie schreiben sie selbst in die Erweiterungsmethode. Dies ist in einigen Fällen tatsächlich nützlich:

public static bool IsNullOrEmpty(this string value)
{
    return string.IsNullOrEmpty(value);
}
public static void ThrowIfNull<T>(this T obj, string parameterName)
        where T : class
{
    if(obj == null) throw new ArgumentNullException(parameterName);
}

usw.

Grundsätzlich sind Aufrufe zu statischen Aufrufen sehr wörtlich zu nehmen - d.h.

string s = ...
if(s.IsNullOrEmpty()) {...}

wird:

string s = ...
if(YourExtensionClass.IsNullOrEmpty(s)) {...}

wo es offensichtlich keine Nullprüfung gibt.

54voto

Stefan Steinegger Punkte 62197

Ergänzung zur richtigen Antwort von Marc Gravell.

Sie könnten eine Warnung vom Compiler erhalten, wenn es offensichtlich ist, dass dieses Argument null ist:

default(string).MyExtension();

Funktioniert zur Laufzeit gut, erzeugt aber die Warnung "Expression will always cause a System.NullReferenceException, because the default value of string is null" .

34voto

Jordão Punkte 53117

Wie Sie bereits herausgefunden haben, sind Erweiterungsmethoden einfach glorifizierte statische Methoden und werden mit null Referenzen übergeben, ohne ein NullReferenceException geworfen wird. Da sie aber für den Aufrufer wie Instanzmethoden aussehen, sollten sie auch sich verhalten als solche. Sie sollten dann in den meisten Fällen die this Parameter und lösen eine Ausnahme aus, wenn er null . Es ist in Ordnung, dies nicht zu tun, wenn sich die Methode ausdrücklich um die null Werte und ihr Name gibt sie ordnungsgemäß an, wie in den folgenden Beispielen:

public static class StringNullExtensions { 
  public static bool IsNullOrEmpty(this string s) { 
    return string.IsNullOrEmpty(s); 
  } 
  public static bool IsNullOrBlank(this string s) { 
    return s == null || s.Trim().Length == 0; 
  } 
}

Ich habe auch geschrieben einen Blogbeitrag darüber schon vor einiger Zeit.

22voto

Binary Worrier Punkte 49250

An die Erweiterungsmethode wird ein Nullwert übergeben.

Wenn die Methode versucht, auf das Objekt zuzugreifen, ohne zu prüfen, ob es null ist, dann ja, dann wird eine Ausnahme ausgelöst.

Ein Typ hier schrieb "IsNull" und "IsNotNull" Erweiterungsmethoden, die prüfen, ob die übergebene Referenz null ist oder nicht. Persönlich denke ich, dies ist eine Anomalie und sollte nicht das Licht der Welt gesehen haben, aber es ist völlig gültig c#.

12voto

Zoran Horvat Punkte 10033

Wie bereits erwähnt, führt der Aufruf einer Erweiterungsmethode mit einer Null-Referenz dazu, dass dieses Argument Null ist und nichts anderes passiert. Dies bringt uns auf die Idee, Erweiterungsmethoden zu verwenden, um Schutzklauseln zu schreiben.

Beispiele finden Sie in diesem Artikel: Wie man die zyklomatische Komplexität reduziert: Schutzklausel Die Kurzfassung lautet wie folgt:

public static class StringExtensions
{
    public static void AssertNonEmpty(this string value, string paramName)
    {
        if (string.IsNullOrEmpty(value))
            throw new ArgumentException("Value must be a non-empty string.", paramName);
    }
}

Dies ist die Erweiterungsmethode der String-Klasse, die bei einer Null-Referenz aufgerufen werden kann:

((string)null).AssertNonEmpty("null");

Der Aufruf funktioniert nur deshalb gut, weil die Laufzeit die Erweiterungsmethode bei einer Null-Referenz erfolgreich aufrufen wird. Dann können Sie diese Erweiterungsmethode verwenden, um Guard-Klauseln ohne umständliche Syntax zu implementieren:

    public IRegisteredUser RegisterUser(string userName, string referrerName)
    {

        userName.AssertNonEmpty("userName");
        referrerName.AssertNonEmpty("referrerName");

        ...

    }

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X