Способы приведения объектов к общему типу

В отношении приведения общего типа к типу T при принудительном применении тип T

И на следующем примере

private static T deserialize<T>(string streng) where T : class
{
    XmlSerializer ser = new XmlSerializer(typeof(T));
    StringReader reader = new StringReader(streng);
    return ser.Deserialize(reader) as T;
}

а также

private static T deserialize<T>(string streng)
{
    XmlSerializer ser = new XmlSerializer(typeof(T));
    StringReader reader = new StringReader(streng);
    return (T)ser.Deserialize(reader);
}

Я привык делать кастинг object as Type, поэтому я был немного сбит с толку, когда обнаружил, что не могу просто сделать это с T. Затем я нашел вопрос выше и в нем решение ошибки компилятора as T.

Но почему where T : class необходимо при использовании object as T, а не при использовании (T)object? Какова фактическая разница между двумя способами приведения объекта?


person Heki    schedule 21.12.2010    source источник
comment
О да, спасибо, абатищев. Гораздо аккуратнее без пространств имен :)   -  person Heki    schedule 21.12.2010


Ответы (4)


Поскольку as подразумевает, что приведение может завершиться ошибкой и вернуть null. Без : class T может быть int и т. д., чего не может быть null. С (T)obj он просто взорвется с градом искр; нет необходимости обрабатывать null.

В качестве отступления (относительно struct) обратите внимание, что вы можете использовать as, если известно, что вы выполняете приведение к Nullable<>, например:

static T? Cast<T>(object obj) where T : struct
{
    return obj as T?;
}
person Marc Gravell    schedule 21.12.2010
comment
Это очень информативно. Я бы принял ваш ответ, но система говорит мне подождать восемь минут. - person Heki; 21.12.2010
comment
Документацию MSDN можно найти здесь: msdn.microsoft. com/en-us/library/cscsdfbt(v=VS.100).aspx (для дальнейшего чтения) - person Jonas Van der Aa; 21.12.2010

Приведение с «как» указано для 1) выполнения приведения, если оно может, и 2) возврата null, если оно не может. Это проблематично с неограниченным универсальным параметром (ваш второй пример), потому что T может быть типом значения (например, int), переменные которого не могут содержать null.

Когда ваш универсальный параметр ограничен ссылочным типом (с ограничением class), компилятор может немного больше рассуждать о вашем типе и понять, что null всегда будет допустимым значением для типа T. Поэтому стиль «как» литье можно смело использовать.

person Ben    schedule 21.12.2010

Поскольку оператор as возвращает null в случае неудачи, переменная должна быть классом или структурой, допускающей значение null:

Между тем cast ничего подобного не требует, и вы можете привести структуру к структуре.

person abatishchev    schedule 21.12.2010

(T)obj бросает, если obj не конвертируется в T. Вам следует использовать (T)obj, если вы уверены, что преобразование будет работать.

И используйте as, чтобы заменить тест на is, за которым следует приведение. Конечно, T должен быть обнуляемым (либо ссылочным типом, либо Nullable<T>), поскольку as возвращает null в случае ошибки. Типичный образец:

T x=y as T;
if(x!=null)
  DoSomething(x);

Еще одно отличие состоит в том, что as работает только для части конверсий. Перегруженные приведения и т. д. будут игнорироваться.

person CodesInChaos    schedule 21.12.2010
comment
примечание: поскольку Deserialize возвращает object, другие преобразования в любом случае не применяются - person Marc Gravell; 21.12.2010
comment
Да, и в этом случае он все равно должен использовать приведение (T)x, так как он знает, что результат имеет тип T. - person CodesInChaos; 21.12.2010