Новой функцией C# 12 являются встроенные массивы, например
[System.Runtime.CompilerServices.InlineArray(10)]
public struct Buffer
{
private object element;
}
как описано здесь.
Если я определяю экземпляр такого массива, например
Buffer a = new();
Я ожидал, что что-то вроде a.Size
или a.Length
будет определено как свойство или метод, но это не так.
Я нашел такой способ получить длину буфера: ((ReadOnlySpan<double>)a).Length
. Есть ли более элегантный способ?
[System.Runtime.CompilerServices.InlineArray(Buffer.Length)]
public struct Buffer
{
private object element;
public const int Length = 10; // Define the length as a constant
}
Buffer a = new();
var length = Buffer.Length;
Или
[System.Runtime.CompilerServices.InlineArray(Buffer.length)]
public struct Buffer
{
private object element;
private const int length = 10; // Define the length as a constant
public int Length => length;
}
Buffer a = new();
var length = a.Length;
В этом примере свойство Длина определяется непосредственно в структуре, что обеспечивает более интуитивный способ доступа к длине буфера. Это свойство просто возвращает постоянный размер встроенного массива. Однако имейте в виду, что этот подход требует ручной синхронизации значения свойства Длина с фактическим размером, определенным в атрибуте InlineArray.
Это не так динамично, как получение длины из ReadOnlySpan, который адаптируется к фактическому типу и размеру буфера, но обеспечивает понятный и простой интерфейс для доступа к длине.
Я предлагаю определить константу: public const int Length = 10;
, которую вы можете использовать в атрибуте: [System.Runtime.CompilerServices.InlineArray(Buffer.Length)]
Я хотел бы сделать модификацию Дмитрия ответа Альберто принятой. Может ли кто-нибудь из вас создать эту версию как новый ответ или изменить существующую?
@MarkusParker обновил код из ОП, чтобы он соответствовал запросу.
Язык обеспечит типобезопасный и безопасный по ссылкам способ доступа к элементам встроенных типов массивов. Доступ будет основан на интервале.
Где в следующем разделе рассказывается, как получить интервал.
То есть от вас не ожидается прямого доступа к размеру переменной или членам длины. Вместо этого вы получаете Span и используете его для управления массивом. Кроме того, поскольку массивы имеют фиксированный размер, вы уже должны знать .Length
на основе аргумента атрибута, указанного при объявлении структуры.
Я ожидал, что что-то вроде
a.Size
илиa.Length
будет определено как свойство или метод, но это не так.
К сожалению на данный момент ничего из коробки нет. Как написано в обсуждении в csharplang:
InlineArray
предназначен для скрытого резервного хранилища, которое не используется напрямую. Вместо этого вы можете просто свободно обернуть его как диапазон и затем получить все тонкости этой абстракции более высокого уровня.
И
Честно говоря, единственный ответ здесь — просто привести его к
Span<T>
, а затем получить длину. Он преодолевает некоторые препятствия, но, по крайней мере, среда выполнения кажется вполне способной сложить все и просто вернуть постоянное значение.
В основном то, что вы уже обнаружили:
Buffer a = new();
Console.WriteLine(((Span<object>)a).Length);
Использование оператора диапазона ([..]
, который выглядит немного более эзотерично, но гораздо короче) приводит к созданию того же IL-кода:
Console.WriteLine(a[..].Length);
// decompiled generated code
Console.WriteLine(<PrivateImplementationDetails>.InlineArrayAsSpan<Buffer, object>(ref buffer, 10).Length);
Как вариант, вы можете написать генератор исходного кода, который будет генерировать некоторые методы расширения для всех встроенных массивов.
P.S.
Утверждение «но, по крайней мере, среда выполнения кажется вполне способной сложить все и просто вернуть постоянное значение» - утверждение кажется неверным, основываясь на JIT ASM, созданном Sharplab.io.
«по крайней мере, среда выполнения кажется вполне способной складывать все и просто возвращать постоянное значение», похоже, не поддерживается JIT ASM в Sharplab
@Charlieface да, у меня тоже возникло такое чувство, глядя на это, но у него не было времени исследовать больше. Обновлю ответ, спасибо.
можешь попробовать
a[..].Length