В С#, что происходит, когда вы вызываете метод расширения на нулевом объекте?
Вызывается ли метод с нулевым значением или он дает исключение ссылочной ссылки?
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 нарушен... вы собираетесь выполнить некоторую логику на нулевом экземпляре.