Почему общие структуры не могут быть неуправляемыми? - PullRequest
0 голосов
/ 08 ноября 2018

Пожалуйста, посмотрите на этот код:

namespace ConsoleApp
{
    public struct MyPoorGenericStructThatCannotBeUnmanaged<T> where T: unmanaged
    {
        public T Field;
    }

    public class MyClass<T> where T: unmanaged
    {
    }

    class Program
    {
        static void Main()
        {
            // The type 'MyPoorGenericStructThatCannotBeUnmanaged<int>' must be a non-nullable value type, 
            // along with all fields at any level of nesting, 
            // in order to use it as parameter 'T' in the generic type or method 'MyClass<T>'
            var obj = new MyClass<MyPoorGenericStructThatCannotBeUnmanaged<int>>(); 
        }
    }
}

Не удается скомпилировать с ошибкой:

Тип 'MyPoorGenericStructThatCannotBeUnmanaged' должен быть ненулевым типом значения, наряду свсе поля на любом уровне вложенности, чтобы использовать его в качестве параметра 'T' в универсальном типе или методе 'MyClass'

Однако MyPoorGenericStructThatCannotBeUnmanaged<int> является типом значения, не допускающим значения NULL, и всеего поля при любом значении вложенности действительно являются необнуляемыми типами значений.Это обеспечивается общим ограничением типа where T: unmanaged

Почему?

1 Ответ

0 голосов
/ 08 ноября 2018

До тех пор, пока ограничение не будет устранено, вы можете использовать обходной путь на основе Unsafe.

Вот как может выглядеть обходной путь:

public unsafe class ArrayOfGenericStructs<TStruct> : IDisposable where TStruct:struct
{
    private void* pointer;

    public ArrayOfGenericStructs(int size)
    {
        pointer = (void*) Marshal.AllocHGlobal(Unsafe.SizeOf<TStruct>() * size);
    }

    public bool IsDisposed { get; private set; }

    public void Dispose()
    {
        if (IsDisposed) return;
        IsDisposed = true;
        if (pointer != null) Marshal.FreeHGlobal(new IntPtr(pointer));
        pointer = null;
    }

    public ref TStruct this[int index]
    {
        get
        {
            return ref Unsafe.AsRef<TStruct>(Unsafe.Add<TStruct>(pointer, index));
        }
    }
}
...