В C#, что происходит, когда вы вызываете метод расширения на нулевом объекте?


метод вызывается с нулевым значением или он дает исключение нулевой ссылки?

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

Если это так, мне никогда не нужно будет проверять мой параметр "this" на null?

7   264   2009-05-11 12:35:27

7 ответов:

Это будет работать нормально (без исключения). Методы расширения не используют виртуальные вызовы (т. е. он использует инструкцию "call" il, а не "callvirt"), поэтому нет нулевой проверки, если вы не напишете ее самостоятельно в методе расширения. Это действительно полезно в нескольких случаях:

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

etc

По сути, вызовы статических вызовов очень буквальны-т. е.

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

будет:

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

где, очевидно, нет нулевой проверки.

дополнение к правильному ответу от Marc Gravell.

вы можете получить предупреждение от компилятора, если очевидно, что этот аргумент равен null:

default(string).MyExtension();

хорошо работает во время выполнения, но обеспечивает предупреждение "Expression will always cause a System.NullReferenceException, because the default value of string is null".

как вы уже обнаружили, поскольку методы расширения-это просто прославленные статические методы, они будут вызываться с null ссылки передаются без NullReferenceException быть брошенным. Но, поскольку они выглядят как методы экземпляра для вызывающего объекта, они также должны вести как таковой. Затем вы должны, большую часть времени, проверять this параметр и бросить исключение, если это null. Это нормально не делать этого, если метод явно заботится о null значения и его название указывает на это должным образом, как в приведенных ниже примерах:

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

Я написал блоге об этом некоторое время назад.

в метод расширения будет передано значение null.

Если метод пытается получить доступ к объекту без проверки, это null, то да, он будет бросать исключение.

парень здесь написал" IsNull "и" IsNotNull " методы расширения, которые проверяют, является ли ссылка переданной null или нет. Лично я думаю, что это аберрация и не должен был видеть свет дня, но это совершенно правильный c#.

как указывали другие, вызов метода расширения по нулевой ссылке приводит к тому, что этот аргумент равен нулю, и ничего особенного не произойдет. Это дает повод к идее использовать методы расширения для написания защитных предложений.

вы можете прочитать эту статью для примера: Как уменьшить Цикломатическую сложность: Guard Clause этой

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

Это метод расширения класса string, который может быть вызван на null ссылка:

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

вызов работает нормально только потому, что среда выполнения успешно вызовет метод расширения по нулевой ссылке. Затем вы можете использовать этот метод расширения для реализации предложений guard без беспорядочного синтаксиса:

    public IRegisteredUser RegisterUser(string userName, string referrerName)
    {

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

        ...

    }

extensionmethod является статическим, поэтому, если вы ничего не делаете с этим MyObject, это не должно быть проблемой, быстрый тест должен проверить это :)

есть несколько золотых правил, когда вы хотите, чтобы ваш был читаемым и вертикальным.

  • стоит сказать, что Эйфель говорит, что конкретный код, инкапсулированный в метод, должен работать против некоторого ввода, что код работоспособен, если выполняются некоторые предварительные условия и обеспечивают ожидаемый результат

в вашем случае - DesignByContract нарушен ... вы собираетесь выполнить некоторую логику на нулевом экземпляре.