Подтвердить что ты не робот

Использует ли "как" на С# безопасный способ литья?

Мне интересно, является ли использование ключевого слова "как" в следующем коде безопасным способом (т.е. не взорвать) литья в С#:

public void abc(ref Object dataSource)
{
    DataTable table = dataSource as DataTable;
}

Если есть более безопасный способ кастинга, сообщите мне об этом. Я новичок в С# и еще не знаю, как это сделать.

Спасибо!: D

4b9b3361

Ответ 1

Он не взорвется... но это не обязательно означает, что это безопасно.

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

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

as хорош, если он действителен для того, чтобы объект не был данного типа - если он не указывает на ошибку. Вы почти всегда видите шаблон:

Foo x = y as Foo;
if (x != null)
{
    ...
}

Подробнее о том, что делает as, см. MSDN.

Обратите внимание, что вы, вероятно, не хотите использовать ref в своем методе. Дополнительную информацию см. В статье о передаче параметров. В большинстве случаев, если я часто вижу людей, использующих ref, потому что они не понимают, что это на самом деле означает:)

Ответ 2

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

Как вы, наверное, знаете, есть два основных способа сделать явное литье в С#:

foo = (MyType)myObject;    //Cast myObject to MyType or throw an error
foo = myObject as MyType;  //Cast myObject to MyType or set foo to null

Разница в том, что если среда выполнения не знает, как отличить myObject как MyType, первая строка выдает исключение, а вторая устанавливает только foo в null. Это произойдет, если объект, живущий в myObject, не является MyType, или если нет явного приведения к MyType из любого myObject.

Итак, какой из них безопаснее? Ну, если "безопасный" означает "не будет выдавать исключение, если приведение недействительно", тогда форма as безопаснее. Если сбой кастования, (MyType)myObject немедленно взорвется, но myObject as MyType будет только взорваться, если вы попытаетесь сделать что-то с foo, что вы не можете сделать с null (например, вызов foo.ToString()).

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

Таким образом, ни одна из форм не является по своей сути безопасной или правильной, они просто полезны для разных вещей. Вы должны использовать форму myObject as MyType, если:

  • Вы точно не знаете, какой тип myObject
  • Вы хотите что-то сделать с помощью myObject, но только если это тип MyType
  • myObject может быть чем-то иным, чем MyType, и это не будет означать ошибку

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

foreach (var control in controls)
{
    var textbox = control as TextBox;
    if (textbox != null)
    {
        //Now we know it a TextBox, so we know it has a Text property
        textbox.Text = string.Empty;
    }
}

Таким образом, ваши TextBoxes будут очищены, а все остальное останется в покое.

Ответ 3

DataTable table = dataSource as DataTable;

Использование as вернет null, если бросок не увенчался успехом, поэтому он не взорвется. - это означает, что вам придется обрабатывать случай, когда table есть null в остальной части вашего кода.

Ответ 4

as не взорвется, но если приведение не выполнено, переменная будет установлена ​​в значение null. Вам нужно проверить этот случай.

DataTable table = dataSource as DataTable;
if (table == null)
{
    // handle case here.
}

Ответ 5

Оператор 'as' не будет генерировать исключение, если приведение недействительно. Он просто возвращает null. Подход() вызовет исключение. Поэтому, чтобы ответить на ваш вопрос, это самый безопасный способ.

Вот, по сути, вам нужно это сделать:

if( x is MyType )
{
   MyType y = (MyType) x;
}

или

MyType y = x as MyType;
if( y != null )
{
   // Do stuff
}

Ответ 6

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

При использовании as, если выдача не выполняется, результирующая переменная null. Если вы не проверите это, вы позже получите NullReferenceException при попытке получить доступ к переменной, и будет меньше понятно, почему она не работает (например, это null, потому что приведение отказало или что-то еще позже, чтобы оно было нулевым)

Ответ 7

Он не будет генерировать исключение, если это то, что вы подразумеваете под "безопасным". Однако, если сбой выполняется, table будет null.

DataTable table = dataSource as DataTable;

Не генерирует исключения, если сбой выполняется. Вместо этого будет null.

DataTable table = (DataTable)dataSource;

Будет выдано исключение, если сбой выполняется.

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

Ответ 8

Зависит от того, что вы пытаетесь сделать:

DataTable table = dataSource as DataTable;
if (table != null) ...

означает, что "dataSource может быть DataTable, и я собираюсь проверить его не на null."

DataTable table = (DataTable) dataSource;

означает, что "dataSource обязательно должен быть DataTable и что-то плохое, если это не так".

Ответ 9

Это безопасно в том смысле, что он выполнит свою работу, если dataSource может быть запущен как DataTable. Но если вы беспокоитесь о том, что он не успешно выполняет кастинг, вы можете сначала проверить, равен ли dataSource.GetType() тип, к которому вы пытаетесь применить его.

Ответ 10

Если вы используете as, будет исключение InvalidCastException, но таблица может быть нулевой, поэтому вам нужно проверить это.

Ответ 11

Разница между использованием as и нормальным литом заключается в том, что если приведение не может быть выполнено (поскольку объект не является правильным типом), оператор as возвращает null. Обычный бросок выдает исключение.

Итак, они оба "безопасны" - у них просто разные поведения, когда приведение не может быть успешным.