Страницы

Поиск по вопросам

понедельник, 9 декабря 2019 г.

Существуют ли какие-то затраты на преобразование объектов?

#c_sharp #net #преобразование_типов


С преобразованием значимого типа в объект и обратно все понятно — там появляются
доп. операции на упаковку/распаковку.

А есть ли какие-то затраты при преобразовании объектов между дочерним типом и базовым
типом?
    


Ответы

Ответ 1



Неявные преобразования Неявные преобразования проверяются компилятором и после компиляции уже не существуют, соответственно, дополнительных затрат не требуют. Это можно проверить, прочитав IL-код после компиляции: Код на C#: class A{} class B : A{} ... B b = new B(); A a = new A(); A target; target = b; Console.WriteLine(target); target = a; Console.WriteLine(target); Сгенерерированный IL: IL_0001: newobj instance void B::.ctor() //new B() IL_0006: stloc.0 //b = IL_0007: newobj instance void A::.ctor() //new A() IL_000c: stloc.1 //a = IL_000d: ldloc.0 IL_000e: stloc.2 IL_000f: ldloc.2 IL_0010: call void [mscorlib]System.Console::WriteLine(object) IL_0015: nop IL_0016: ldloc.1 IL_0017: stloc.2 IL_0018: ldloc.2 IL_0019: call void [mscorlib]System.Console::WriteLine(object) Как видно, в обоих случаях генерируется пара инструкций ldloc (загрузка переменной в стек) и stloc (выгрузка из стека в переменную). Никаких дополнительных телодвижений при преобразовании типа не выполняется. Аналогично, если Вы вызываете метод вида: A a = someClass.generateA(), то среда выполнения не проверяет реальный тип объекта, который вернулся из A, ожидая, что компилятор уже выполнил проверку соответствия типов. Явные преобразования Явные преобразования генерируют дополнительные инструкции, которые требуют определенных затрат. Приведение типа — инструкцию castclass, преобразования через as и is — isinst. Обе эти инструкции описаны в спецификации CLI. Соответственно, код на C#: A a = new B(); Console.WriteLine((B) a); Console.WriteLine(a as B); Console.WriteLine(a is B); будет преобразован в следующий IL: IL_0001: newobj instance void B::.ctor() IL_0006: stloc.0 IL_0007: ldloc.0 IL_0008: castclass B IL_000d: call void [mscorlib]System.Console::WriteLine(object) IL_0012: nop IL_0013: ldloc.0 IL_0014: isinst B IL_0019: call void [mscorlib]System.Console::WriteLine(object) IL_001e: nop IL_001f: ldloc.0 IL_0020: isinst B IL_0025: ldnull IL_0026: cgt.un IL_0028: call void [mscorlib]System.Console::WriteLine(bool) Если типы не сходятся, то castclass сгенерирует исключение, что несколько более затратно. Соответственно, если вероятность этого высока, то лучше применять as чем cast. В случае когда типы сходятся ощутимой разницы быть не должно. Обе инструкции применяются очень часто, работают быстро и крайне оптимизированы. Навряд ли приведение типа будет узким местом в Вашем коде, поэтому в большинстве случаев важно писать то приведение, которое имеет больше смысла и лучше читается. Достаточно обширное обсуждение разницы as vs cast на английском Stack Overflow: Casting vs using the 'as' keyword in the CLR

Комментариев нет:

Отправить комментарий