Как получить представление структуры Span <byte>без ключевого слова unsafe - PullRequest
0 голосов
/ 11 мая 2018

Как можно создать представление Span<byte> (переинтерпретация) из одного значения структуры без копирования, выделения и без ключевого слова unsafe .

В настоящее время я могу выполнить это только с помощью ключевого слова unsafe:

public unsafe Span<byte> AsSpan<T>(in T val) where T : unmanaged
{
    void* valPtr = Unsafe.AsPointer(ref Unsafe.AsRef(val));
    return new Span<byte>(valPtr, Marshal.SizeOf<T>());
}

// Alternatively, slightly easier when using 'ref' instead of 'in'
public unsafe Span<byte> AsSpan<T>(ref T val) where T : unmanaged
{
    void* valPtr = Unsafe.AsPointer(ref val);
    return new Span<byte>(valPtr, Marshal.SizeOf<T>());
}

При работе с массивом, а не с одним значением - это легко и безопасно сделать с помощью MemoryMarshal.Cast<TTo, TFrom>( ... ), например:

public Span<byte> AsSpan<T>(Span<T> vals) where T : unmanaged
{
    return MemoryMarshal.Cast<T, byte>(vals);
}

Использование netstandard2.0, последней языковой версии C# 7.3 и последних пакетов RC для System.Memory и System.Runtime.CompilerServices.Unsafe:

<PropertyGroup>
   <TargetFramework>netstandard2.0</TargetFramework>
   <LangVersion>7.3</LangVersion>
</PropertyGroup>
<ItemGroup>
   <PackageReference Include="System.Memory" Version="4.5.0" />
   <PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.5.0" />
</ItemGroup>

Edit: Что касается ответов о безопасности / повреждении памяти - общее ограничение unmanaged, введенное в C # 7.3, может заменить общее ограничение struct и позволить сделать это безопасным для памяти способом.

См .: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters

where T : unmanaged Аргумент типа не должен быть ссылочным типом и не должен содержать членов ссылочного типа на любом уровне вложенности.

Ответы [ 2 ]

0 голосов
/ 07 июня 2018

Мне кажется, что оба ваших небезопасных метода могут испортить память. Поэтому их нельзя использовать без надлежащих ограничений.

1) Если структура была размещена в стеке, вы должны использовать возвращаемый span только глубже в том же стеке. Если вы вернете его вызывающему методу, вы получите неверный указатель.

2) Если структура находилась в куче, GC может перемещаться с ссылочным типом. Вы можете быть повреждены в любое время. Использовать исправленный экземпляр контейнера.

3) Если структура была размещена в собственной памяти, есть слишком много опций ...

0 голосов
/ 18 мая 2018

Частичное решение:

Если нацелен на netcoreapp, а не на netstandard2.0, то в netcoreapp2.1 доступен API (доступен для скачивания здесь на дату этого комментария).


Использование:

using System.Runtime.InteropServices;

public Span<byte> AsSpan<T>(ref T val) where T : unmanaged
{
    Span<T> valSpan = MemoryMarshal.CreateSpan(ref val, 1);
    return MemoryMarshal.Cast<T, byte>(valSpan);
}

Это , а не решение вопроса, который запрашивает эту возможность в netstandard2.0. Тем не менее, это должно быть полезно для многих, кто сталкивается с этим.

...