В новой версии превью Visual Studio "15" появилась вот такая конструкция, которая возвращает ссылку на объект:
static void Main(string[] args)
{
int[] numbers = { 0b1, 0b10, 0b100, 0b1000, 0b1_000, 0b10_0000 };
ref int r = ref Find(numbers, x => x > 4);
WriteLine($"{r} == {numbers[4]}");
r = 0;
WriteLine($"{r} == {numbers[4]}");
}
static ref Find(int[] list, Func
В чем смысл этого нововведения? Разве если мы возвращаем объект из метода, то мы его не возвращаем неявно ссылку на него?
Так же появились локальные функции. В чем их юзабельность, разве без них обойтись нельзя? На мой взгляд это понизит качество кода, так как со стороны функция будет похожа на класс с методами.
class Program
{
int[] numbers = { 0b1, 0b10, 0b100, 0b1000, 0b1_0000, 0b10_0000 };
(int, int) Tally(IEnumerable
}
}
Ответ
По первой части, это интересно для типов-значений.
С ссылочными типами нет особой разницы, работаете вы с объектом по оригиналу ссылки или по её копии. Но с типами-значениями, такими как int, вы получаете копию значения. Для возвращаемого ref вы можете работать таки с оригиналом.
Таким образом, вы уменьшаете объём копирования структур (которое может быть проблемой в высокопроизводительном коде).
Кроме того, вы сможете писать код наподобие «найти точку с наибольшим X и увеличить у неё Y», потому что судя по всему станут возможны функции наподобие
ref Point MaxBy(Point[] points, Func
ref Point rightmost = MaxBy(points, p => p.X);
rightmost.Y += 1;
По поводу локальных функций, мне кажется, часто, наоборот, приватные функции классов используются как костыль на отсутствие локальных функций. Часто в приватную функцию выносится хелпер из одной функции, не имеющий значения внутри класса. Локальная функция — более правильный путь для таких функций.
Дополнительно, локальные функции «видят» локальные переменные в охватывающей функции, а значит, вам не придётся передавать в них кучу вспомогательных аргументов.
Ещё один юзкейс для локальных функций — итераторы и async-функции. Смотрите. Если у вас есть код
IEnumerable
— то проверка будет выполнена, и исключение брошено лишь после начала перечисления. То есть код
IEnumerable
не поймает исключение. То есть, пользователю придётся знать, будет ли исключение брошено во время вызова или во время перечисления.
С локальными функциями вы можете написать так:
IEnumerable
Исключение будет при этом брошено сразу, при вызове GetOdd, а не при перечислении. Очевидно, что внутренняя функция имеет смысл лишь для GetOdd, так что не стоит заводить для неё отдельную функцию на внешнем уровне, пусть даже и приватную.
Комментариев нет:
Отправить комментарий