Comments 32
Упаковка действительно «тяжёлая» операция, так как требует выделения памяти. Распаковка — нет, это только копирование. При прямой работе со структурами тоже происходит копирование. Так что при распаковке никаких особых потерь в скорости нет.
MSDN с вами не согласен.
Цит. (смысловой перевод): упаковка и распаковка — дорогие операции. При упаковке типа значения должен быть создан новый объект. Такая операция может занять до 20 раз больше времени, чем присваивание. При распаковке операция приведения может занять в 4 раза больше времени, чем нужно для присваивания (а распаковка, как известно, всегда сопровождается явным приведением).
Цит. (смысловой перевод): упаковка и распаковка — дорогие операции. При упаковке типа значения должен быть создан новый объект. Такая операция может занять до 20 раз больше времени, чем присваивание. При распаковке операция приведения может занять в 4 раза больше времени, чем нужно для присваивания (а распаковка, как известно, всегда сопровождается явным приведением).
Мне тоже кажется, что ребята из Microsoft завышают расценки — в 20 раз, в 4 раза. Однако часть проблемы в том, что операции упаковки-распаковки в некотором смысле «парные» — если есть упаковка, значит где-то понадобится и распаковка (не факт, конечно). Второе — это неявное создание копии объекта, что тоже нужно держать в уме. Всё это сочетание всё же достаточно существенно снижает производительность, чтобы сделать выбор, например, в сторону обобщений вместо object или dynamic.
Не думаю, что вселенная взорвётся от того, что где-то в коде произойдёт десяток упаковок-распаковок. Но на коллекциях объектов, при массовых «перепаковках» всё же стоит задуматься о производительности.
Не думаю, что вселенная взорвётся от того, что где-то в коде произойдёт десяток упаковок-распаковок. Но на коллекциях объектов, при массовых «перепаковках» всё же стоит задуматься о производительности.
Плюнь на MSDN. Вот код теста.
pastebin.com/zMReV0Bj
У меня он выводит:
Boxing: 00:00:13.9155034
Unboxing: 00:00:00.9500705
Copying: 00:00:00.7068114
pastebin.com/zMReV0Bj
У меня он выводит:
Boxing: 00:00:13.9155034
Unboxing: 00:00:00.9500705
Copying: 00:00:00.7068114
если вы действительно хотите поговорить про «тонкие моменты», то не говорите, что value – stack; reference – heap. посмотрите сначала на то, что пишет Эрик Липперт blogs.msdn.com/b/ericlippert/archive/2010/09/30/the-truth-about-value-types.aspx
да и остальное на тонкости не сильно тянет.
да и остальное на тонкости не сильно тянет.
Хм. Ну раз тут «тонкости», то можно и позанудствовать.
>> Ссылочные типы (...) хранятся в управляемой куче
Не типы, а инстансы объектов этих типов. Сами типы хранятся тоже в аналоге кучи, но CLR вас в той куче видеть не хотела бы.
>> кроме случая, когда тип значения является полем класса
Неправда. Вы забыли про массивы
>> [Про рефлексию]… соблюдая принцип инкапсуляции.
Не забудьте соблюсти permissions, ибо под FullTrust != всегда
Ни о чем, если честно. Какова объединяющая мысль статьи?
>> Ссылочные типы (...) хранятся в управляемой куче
Не типы, а инстансы объектов этих типов. Сами типы хранятся тоже в аналоге кучи, но CLR вас в той куче видеть не хотела бы.
>> кроме случая, когда тип значения является полем класса
Неправда. Вы забыли про массивы
>> [Про рефлексию]… соблюдая принцип инкапсуляции.
Не забудьте соблюсти permissions, ибо под FullTrust != всегда
Ни о чем, если честно. Какова объединяющая мысль статьи?
1) Да, конечно, имеются ввиду экземпляры объектов ссылочного типа. Другое дело, что опускаю эти «подробности» не один я.
2) Тут можно немного пофилософствовать на тему того, что массивы в платформе .NET Framework реализуются как экземпляры класса System.Array, но если рассматривать массив как структуру данных, то вы правы. Массив — ссылочный тип, следовательно, память для него распределяется в куче.
3) А можно поподробнее?
Объединяющая мысль статьи — в C# есть особенности/возможности, о которых вы можете не знать/догадываться. Да прибудет с вами знание этой статьи!
2) Тут можно немного пофилософствовать на тему того, что массивы в платформе .NET Framework реализуются как экземпляры класса System.Array, но если рассматривать массив как структуру данных, то вы правы. Массив — ссылочный тип, следовательно, память для него распределяется в куче.
3) А можно поподробнее?
Объединяющая мысль статьи — в C# есть особенности/возможности, о которых вы можете не знать/догадываться. Да прибудет с вами знание этой статьи!
>> А можно поподробнее?
blogs.msdn.com/b/shawnfa/archive/2005/03/08/389768.aspx годится?
>> да пребудет с вам
нет, спасибо :)
blogs.msdn.com/b/shawnfa/archive/2005/03/08/389768.aspx годится?
>> да пребудет с вам
нет, спасибо :)
кроме того в сильверлайте не все можно сделать из того, что можно в обычном дотнете
Автор, почитай Рихтера.
То, что ты описал не является чем-то из ряда вон выходящим.
То, что ты описал не является чем-то из ряда вон выходящим.
У меня не было цели написать что-то из ряда вон выходящего. Всё мною описанное прямым или косвенным образом следует из спецификации языка, потому что по-другому и быть не может. Ничего не имею против, если кто-то всё это знает, а многие знают и больше. Но многие все учатся, и, надеюсь, я помог прояснить им некоторые моменты, дать небольшие рекомендации, конспективно отображая суть проблемы и её решение.
Я ценю ваш труд, но этот топик из того разряда, что те кому надо уже знают об этом.
Ну раз уж опубликовано, то будем надеятся, что это поможет кому-то.
Если есть желаение написать что-то особенное, то было бы хорошо увидеть тему про взаимодействие managed/unmanaed (как с той, так и с другой стороны) со всеми тонкостями указателей (IntPtr, void* etc.), маршаллинга(Marshal), UnmanagedMemoryStream, StructLayout и прочие.
Ну это так, ИМХО.
Ну раз уж опубликовано, то будем надеятся, что это поможет кому-то.
Если есть желаение написать что-то особенное, то было бы хорошо увидеть тему про взаимодействие managed/unmanaed (как с той, так и с другой стороны) со всеми тонкостями указателей (IntPtr, void* etc.), маршаллинга(Marshal), UnmanagedMemoryStream, StructLayout и прочие.
Ну это так, ИМХО.
В примере про GetEnumerator, типизация не совсем duck.
t в цикле main имеет тип Object.
По моему лучше типизировать:
using System.Collections.Generic;
t в цикле main имеет тип Object.
По моему лучше типизировать:
using System.Collections.Generic;
public IEnumerator GetEnumerator()
*случайно отправилось.
class Sample
{
public IEnumerator GetEnumerator()
…
}
А за СОМ сахар спасибо, не знал.
class Sample
{
public IEnumerator GetEnumerator()
…
}
А за СОМ сахар спасибо, не знал.
В любом случае это не duck.
foreach скрывает как раз вызов метода GetEnumerator() и тип объекта не приводится к IEnumerable
foreach скрывает как раз вызов метода GetEnumerator() и тип объекта не приводится к IEnumerable
UFO just landed and posted this here
Оператор foreach требует, чтобы объект итераций реазизовывал метод с определённой сигнатурой (контракт), но не требует от этого объекта реализации к.-л. интерфейса (такого, как IEnumerable). Если прочитать определение с вики, то именно такое поведение и считается утиной типизацией.
Процитирую:
>> Утиная типизация — вид динамической типизации, применяемой в некоторых языках программирования, когда границы использования объекта определяются его текущим набором методов и свойств, в противоположность наследованию от определённого класса. То есть считается, что объект реализует интерфейс, если он содержит все методы этого интерфейса, независимо от связей в иерархии наследования и принадлежности к какому-либо конкретному классу.
В нашем случае можно сказать, что оператор foreach считает объект коллекцией, если тот реализует метод GetEnumerator().
Процитирую:
>> Утиная типизация — вид динамической типизации, применяемой в некоторых языках программирования, когда границы использования объекта определяются его текущим набором методов и свойств, в противоположность наследованию от определённого класса. То есть считается, что объект реализует интерфейс, если он содержит все методы этого интерфейса, независимо от связей в иерархии наследования и принадлежности к какому-либо конкретному классу.
В нашем случае можно сказать, что оператор foreach считает объект коллекцией, если тот реализует метод GetEnumerator().
>>>При помощи механизма отражения можно изменить значение даже private-поля класса.
Понятно, что применять это строить только в случае крайней необходимости, соблюдая принцип инкапсуляции.
Более того можно менять readonly поля.
Понятно, что применять это строить только в случае крайней необходимости, соблюдая принцип инкапсуляции.
Более того можно менять readonly поля.
после предложения «C# — простой язык, благодаря простоте живёт и PHP.» завис.
этот тонкий момент точно не все знают:
типы значений хранятся в стеке приложения (кроме случая, когда тип значения является полем класса).
этот тонкий момент точно не все знают:
типы значений хранятся в стеке приложения (кроме случая, когда тип значения является полем класса).
Если быть точным, то типы значений храняться в стеке потока.
Если быть точным, то типы значений обычно храняться в стеке потока.
Если быть ещё точнее, то типы значений обычно хранятся в стеке логического управляемого потока .NET, который не обязательно однозначно отображается на физический поток операционной системы.
В итоге имеем: объекты типов значений хранятся в стеке управляемого потока среды .NET, за исключением случаев, когда объект типа значения является полем класса или элементом массива. С другой стороны, объекты ссылочного типа всегда размещаются в управляемой куче процесса.
p.s. Язык C++/CLI позволяет создать массив значений в стеке.
В итоге имеем: объекты типов значений хранятся в стеке управляемого потока среды .NET, за исключением случаев, когда объект типа значения является полем класса или элементом массива. С другой стороны, объекты ссылочного типа всегда размещаются в управляемой куче процесса.
p.s. Язык C++/CLI позволяет создать массив значений в стеке.
Вот вот! Фраза «благодаря простоте живет и PHP» просто убила…
Sign up to leave a comment.
Тонкие моменты C#