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

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

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

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

Ответ 1

Это будет работать отлично (без исключения). В методах расширения не используются виртуальные вызовы (т.е. Он использует инструкцию "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);
}

и т.д.

В принципе, призывы к статическим вызовам очень буквальны - т.е.

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

становится:

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

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

Ответ 2

Дополнение к правильному ответу от Марка Гравелла.

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

default(string).MyExtension();

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

Ответ 3

Как вы уже обнаружили, поскольку методы расширения - это просто прославленные статические методы, они будут вызываться с 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; 
  } 
}

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

Ответ 4

Нуль будет передан методу расширения.

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

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

Ответ 5

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

Вы можете прочитать эту статью для примера: Как уменьшить циклическую сложность: оговорка о защите Краткая версия такова:

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).AssertNonEmpty("null");

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

    public IRegisteredUser RegisterUser(string userName, string referrerName)
    {

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

        ...

    }

Ответ 6

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

Ответ 7

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

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

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