22 сентября 2017
Возможности C#
С# 7 разрешает использовать ключевое слово ref не только для параметров, но так же для возвращаемых значений и локальных переменных. Это позволяет передавать ссылки на структуры вместо самих структур. |
Синтаксис записи:
public ref TReturn MethodName(int index)
{
...
return ref x;
}
// Примеры вызовов
ref TReturn val1 = ref MethodName();
TReturn val2 = MethodName();
Ключевое слово ref используется при указании типа возвращаемого значения при объявлении метода. Так же оно присутствует при непосредственном возврате ссылочного значения.
Созданный метод может быть использован 2 способами:
- С указанием ref: результатом будет ссылочное значение на результат метода.
- Без указания ref: результатом будет копия структуры, как при обычном вызове.
При этом существует ряд ограничений:
- Используя ref можно вернуть только значения, которые безопасны к возврату:
- были изначально переданы в метод
- или ссылаются на поля самого объекта
- Локальные ссылочные переменные не изменяемые (не стоит путать их с ссылками в C++).
Например, нельзя вернуть локальную переменную как ссылочное значение:
public int Get()
{
int value = 42;
return ref value; // Ошибка
}
В качестве примера создадим очень упрощенный пул объектов: зарезервируем массив структур, которые можно будет повторно использовать. В реальном приложении это позволит избежать их частого создания и удаления. Это, в свою очередь, уменьшит нагрузку на сборщик мусора и возможные из-за него паузы в работе.
public class Pool<TStruct>
{
private readonly TStruct[] _pool;
public Pool(int maxPoolSize)
{
this._pool = new TStruct[maxPoolSize];
}
public ref TStruct Get(int index)
{
return ref this._pool[index];
}
}
Вариант его использования:
public struct DemoStruct
{
public int Value;
}
class Program
{
static void Main(string[] args)
{
var pool = new Pool<DemoStruct>(maxPoolSize: 1024);
ref DemoStruct struct1 = ref pool.Get(24);
ref DemoStruct struct2 = ref pool.Get(24);
Console.WriteLine($"ref struct1 = {struct1.Value}");
struct2.Value = 42;
Console.WriteLine($"ref struct1 = {struct1.Value}"); // == 42
DemoStruct struct3 = pool.Get(24);
Console.WriteLine($"struct3 = {struct3.Value}"); // == 42
struct3.Value = 1;
Console.WriteLine($"ref struct1 = {struct1.Value}"); // == 42
Console.WriteLine($"ref struct2 = {struct2.Value}"); // == 42
Console.WriteLine($"struct3 = {struct3.Value}"); // == 1
Console.ReadKey(); }
}
Обратите внимание, что переменные struct1 и struct2 ссылаются на одну и ту же структуру. А struct3 является самостоятельной копией.