#c#
#c#
Вопрос:
Вопрос 1> Должен ли я проверять NULL в следующем случае?
public interface INewClass {}
public class NewClass : INewClass {}
public void FunMeA(INewClass obj)
{
NewClass n = (NewClass) obj;
... // Should I check (n == null) here?
// call methods defined inside INewClass (updated from NewClass to INewClass)
...
}
A concrete example,
public void FunMeB(IAsyncResult itfAR)
{
AsyncResult ar = (AsyncResult) itfAR;
... // Should I check (ar == null) here?
// access ar.AsyncDelegate
...
}
Вопрос 2> Я только начинаю переходить на C # с C .
При написании кода на C я знаю, когда следует выполнить проверку.
Однако я полностью потерялся в мире C #. Итак, вопрос в том, существует ли
общее правило, которое может подсказать мне, когда я ДОЛЖЕН проверять значение NULL?
Спасибо
Комментарии:
1. Если методы определены в интерфейсе INewClass, зачем вы вообще приводите?
2. Просто проверьте, равен ли объект NULL, прежде чем использовать функцию. Идеальная ситуация заключается в том, что к моменту использования метода объект не может иметь значения null, поскольку это требуется для функционирования вашей программы.
Ответ №1:
При выполнении этого:
NewClass n = (NewClass) obj;
В этом нет смысла, потому что, если он не будет приведен, он выдаст недопустимое приведенное исключение.
Если у вас есть какие-либо сомнения относительно того, действительно ли вы можете его привести, вы хотите сделать:
NewClass n = obj as NewClass;
затем
if(n != null) ...
Выполняемое вами приведение называется прямым приведением, при котором система будет предполагать, что оно может быть выполнено. n = obj as NewClass
это называется косвенным приведением и предназначено для тех сценариев, где вы хотите сообщить программе «Эй, я думаю, это сработает, но если нет, не переключайтесь и не создавайте исключение…Я разберусь с этим, если это не сработает.»
Использование is
vs as
при приведении.
В зависимости от того, какой сценарий вы хотите, один будет лучше другого. Технически с точки зрения производительности as
предпочтительнее. .Net будет использовать атомарную попытку приведения к желаемому типу и возвращать null, если это не так, где с is
ему придется дважды обойти дерево наследования, чтобы увидеть, соответствует ли оно этому типу, а затем привести его. Итак, в большинстве случаев, если вы хотите увидеть, хотите ли вы привести и использовать этот тип, лучше:
var obj = o as type
if (obj != null)
в отличие от
if(o is type)
{
var obj = (type);
}
Комментарии:
1. -1: Этот последний абзац не имеет большого смысла. Как вы думаете, как .NET определяет, является ли приведение допустимым с помощью
as
ключевого слова или(SomeType)variable
синтаксиса? Очевидно, что это должно смотреть на дерево наследования. Документация ( msdn.microsoft.com/en-us/library/cscsdfbt.aspx ) говорит, что выражение as эквивалентноexpression is type ? (type)expression : (type)null
за исключением того, что выражение вычисляется только один раз. Кроме того, попробуйте посмотреть на IL. Я скомпилировал выражениеreturn (value as TOut) != null;
, а Reflector разобрал его какreturn (value is TOut);
2. … продолжение: Но IL для
as
оператора содержит 12 инструкций в отличие от 8 дляis
оператора.3. Вы правы, это не имело особого смысла для ОС. Я это исправил.
4. 1 — -1 = 2 … Как тебе такое запутанное двойное отрицательное выражение!
Ответ №2:
Если приведение завершится неудачей, ваш код выдаст исключение.
Используйте is
оператор, чтобы увидеть, сработает ли приведение, и as
для приведения (которое не будет выдавать и возвращать значение null, если приведение завершится неудачей).
Итак:
if(obj is NewClass)
{
//Yay, can cast!
}
Или:
NewClass nc = obj as NewClass;
if(nc != null)
{
//Yay!
}
Комментарии:
1. Но не используйте ‘is’ и ‘as’ вместе. Если вы хотите обработать вероятность того, что приведение недопустимо, используйте ‘as’ с проверкой null.
2. Конечно. Я хочу сказать, что ‘if (x is SomeType) { var y = x as SomeType; … }’ является избыточным.
Ответ №3:
Если вы хотите проверить наличие null, вам следует сделать
NewClass n = obj as NewClass ;
if (n != null)
{
...
}
Но в целом вы могли бы проверить значение null, если это что-то значит в контексте, и вы можете предпринять альтернативные действия. В большинстве случаев вам следует просто позволить ему вызывать исключение NullReferenceException, а не проглатывать его, чтобы вы могли быстрее определить причину нулевой ссылки.
Комментарии:
1. Это назначение не вызовет исключение NullReferenceException, если obj равно null:
NewClass n = (NewClass)obj;
2. @phoog Я хотел сказать, что вы должны проверять значение null, только если вы точно знаете, почему оно равно null, и у вас есть средства справиться с ситуацией. Некоторые люди проверяют наличие null во всем, с чем они работают, и ничего не делают в части else. Это не приводит к исключению нулевого указателя во время выполнения, но когда что-то не так, трудно понять, что не так. В большинстве ситуаций лучше использовать прямое приведение, а не безопасное приведение.
3. Согласен. Очень неприятно, когда программы завершаются беззвучно.
Ответ №4:
Если вы это сделаете NewClass n = (NewClass)obj
, вы получите исключение, если оно не будет приведено должным образом.
Если вы хотите, чтобы была возможность, чтобы оно было null, без создания исключения, вы бы хотели сделать, NewClass n = obj as NewClass;
а затем проверить, n
равно ли это null.
Вы можете проверить, сработает ли приведение заранее, используя is
оператор. if(obj is NewClass)
Надеюсь, это поможет.
Комментарии:
1. Вы можете привести нулевую ссылку. Попробуйте, вам понравится.
Ответ №5:
Если параметр является обязательным, вы всегда должны проверять null
и выдавать ArgumentException
или ArugmentNullException
.
Лучший способ проверки этого параметра здесь:
AsyncResult ar = itfAR as AsyncResu<
if(ar == null)
{
// even better: Use a resource here
throw new ArgumentNullException("Parameter itfAR must not be null and must be of type AsyncResult");
}
Комментарии:
1. @q0987 Также есть
ArgumentOutOfRangeException
, но здесь это, конечно, не имело бы никакого смысла2. Это может вызвать вводящее в заблуждение исключение. Например, если itfAR относится к типу, который реализует IAsyncResult, но не наследует от AsyncResult, вы выдадите исключение ArgumentNullException, даже если аргумент не был равен null. Сбивает с толку.
Ответ №6:
Я предпочитаю проверять значение to на null перед приведением. Например.
if (obj == null)
{
throw new ArgumentNullException("obj", "The argument must has a value specified");
}
Ответ №7:
Вы путаете проблемы.
-
Вы всегда должны проверять аргументы общедоступного метода. Поэтому вы должны сначала сделать:
public WhateEverMethod(элемент IElement) { if (элемент IElement == null) { создать новое исключение ArgumentNullException(…); } }
-
Как только вы подтвердите, что элемент не равен null, вы проверите, можете ли вы выполнить приведение. По сути, вы можете пойти двумя путями:
Элемент element = IElement как элемент;
if (element == null) //приведение не удалось { создать новое исключение InvalidCastException(…); }
или
if (!(iElement is Element))
{
throw new InvalidCastException(...);
}
Element element = (Element)iElement;
Комментарии:
1.
Element element = (Element)(new Object());
в любом случае выдаетInvalidCastException
, так зачем проверять и выбрасывать его в первую очередь!?2. Я поддерживаю точку зрения Саймона. Если недопустимое приведение является исключительным условием, нет смысла самостоятельно создавать недопустимое исключение приведения. Однако, когда я делаю это, я обычно добавляю комментарий, чтобы кто-нибудь другой не подумал, что я упустил из виду возможность недопустимого приведения и изменил мой код:
var theString = (string)obj; // throws an exception if obj is not a string
3. @Simon: Верно, виноват. Я не думал ясно. Однако я хотел бы уточнить, что я бы различал ArgumentNull и InvalidCast . Но, очевидно, да, проверка приведения совершенно не нужна.