Модификатор in, readonly struct и их производительность

dotNET  /  Производительность dotNET  /  CSharp  /  Performance

В прошлом месяце я писал об улучшениях производительности в .NET Core 2.1, а сегодня расскажу о двух фичах C# 7.2 — модификаторе “in” и readonly-структурах.

Рассказ, как обычно, будет коротким. Но со списком статей для дополнительного изучения :) Пара статей Сергея Теплякова и мотивировала меня написать этот краткий конспект на русском языке.

Модификатор in

Обычно в старом добром C# параметры передаются либо по значению, либо по ссылке (с модификатором ref или out). Недавно, в C# 7.2, добавили модификатор in, который работает как ref, но гарантирует, что эту ссылку не поменяют. Ещё одно отличие — можно задавать значение по умолчанию. То есть, можно написать так:

public void Test(in string s = "") { ... } ... Test(); string test = "42"; Test(in test);

и знать, что компилятор не даст поменять ссылку на test в методе Test. Но, поскольку по факту это ref, нельзя вызвать метод так

Test(in "42");

Для чего это полезно? Понятно, что для ссылочных типов пользу найти будет тяжеловато (если сравнивать с передачей этой ссылки по значению). Разве что более явно можно обеспечить то, что параметру ничего не присвоят в методе.

А вот сценариев, когда передаётся структура, которую нельзя менять, дополнительный бонус — можно передать её по ссылке. В этом случае будет передаваться только ссылка на структуру, что должно и экономить память и повысить скорость.

Должно, но это неточно :) Маленький нюанс — для обычной структуры будет создаваться “defensive copy”, чтобы обеспечить её неизменяемость. Поэтому…

readonly struct

В C# 7.2 появились readonly-структуры, гарантирующие свою неизменяемость (забудем на минутку о Reflection). Описываются они просто:

public readonly struct ImmutableStruct

и могут содержать только readonly-поля и get-свойства. Это, само собой, хорошая фича даже просто с точки зрения улучшения качества кода.

А ещё это позволяет избежать создания “defensive copy” для структур, передаваемых с помощью модификатора in. И, заодно, для readonly-полей типа struct (в исходной статье про это подробно написано, с бенчмарками).

Резюме

Конечно, если “readonly” для ваших задач не требуется — можете просто всем этим не пользоваться. Но, если писать вдумчиво, “readonly” будет полезным достаточно часто.

Что касается производительности — понятно, что не всегда выигрыш от readonly struct критичен. Но если это активно используется, то производительность может улучшиться в разы. А для структур в C# придумали столько вкусного, что использоваться структуры будут всё чаще.

Главное: старайтесь использовать (где это логично) readonly struct если используете:

Для дополнительного изучения

dotNET  /  Производительность dotNET  /  CSharp  /  Performance