Как создать неинициализированный 2D-массив?

C# позволяет создавать массив без его инициализации с помощью GC.AllocateUnitializedArray<T>. T может быть любого типа, например bool или int. Однако я не знаю, как сделать это с 2D-массивом, например. bool[,] или int[,].

Я знаю, что могу выделить 1D-массив размером с 2D-массив, а затем получить к нему доступ, как к 2D-массиву, например:

int[] array = GC.AllocateUninitializedArray<int>(width * height); //width and height are width and height of the array
// ... (array is initialized)
int arrayAccessExample = array[x * height + y]; //x and y are anything greater than 0 and less than width and height, respectively

Но постоянно делать это раздражает, и если все сделать неправильно, это может легко привести к ошибкам. Я мог бы превратить доступ к массиву в функцию, которая устранила бы возможность возникновения ошибок, но это все равно неудобно, и я бы предпочел просто иметь возможность использовать настоящий 2D-массив. Есть ли способ напрямую выделить неинициализированный 2D-массив или «привести» 1D-массив к 2D-массиву?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
62
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я бы подумал о том, чтобы пойти по этому пути, чтобы облегчить вам задачу:

public class UnallocatedArray<T>
{
    public UnallocatedArray(int width, int height)
    {
        array = GC.AllocateUninitializedArray<T>(width * height);
        this.Width = width;
        this.Height = height;
    }
    
    private int Width { get; init; }
    private int Height { get; init; }
    
    private T[] array = null;

    public T this[int x, int y]
    {
        get => array[x * this.Height + y];
        set => array[x * this.Height + y] = value;
    }
}

Тогда вы сможете написать:

var ua = new UnallocatedArray<int>(4, 5);
ua[2, 1] = 42;
Console.WriteLine(ua[2, 1]);

Спасибо за быстрый ответ! Вы уверены, что невозможно выполнить приведение из массива 1d в массив 2d? Если нет, ничего страшного — ваш код работает отлично. (редактировать: Чарлифейс, я не знал о существовании Span2D, спасибо!)

CubeX 15.07.2024 03:17

Стоит обратить внимание на порядок следования строк/столбцов, поскольку это может повлиять на совместимость. Встроенный двумерный массив и ваш пример — это основной столбец. В то время как такие вещи, как изображения, почти всегда являются основными строками.

JonasH 15.07.2024 11:58

Есть ли способ напрямую выделить неинициализированный 2D-массив?

Нет, вообще невозможно. Хотя код находится внутри функции AllocateArrayEx в gchelpers.cpp, необязательный параметр flags не предоставляется ни одной функцией FCall или QCall. Поэтому это невозможно сделать даже с помощью отражения без перекомпиляции CLR.

Вы можете и должны открыть задачу GitHub с запросом этой функции, поскольку реализовать ее довольно просто.

или «привести» 1D-массив к 2D-массиву?

Тоже нет. Это совершенно разные типы и даже пути размещения совершенно разные: SZArray (1D, с нулевым индексом) и другие массивы.

Я предполагаю, что теоретически вы могли бы выделить обычный массив, а затем сделать какую-то ужасно небезопасную манипуляцию с m_pMethTab, чтобы заменить его другим, и просто надеяться, что все это «работает», но я бы не стал использовать это в производстве.


Но, на мой взгляд, если ваши требования к производительности достаточно высоки, чтобы требовать неинициализированные массивы, то вам, вероятно, все равно не нужны обычные 2D-массивы, поскольку они имеют значительные накладные расходы из-за отсутствия оптимизации во время выполнения для нескольких массивов. .

В библиотеке ️Span2D Microsoft.Toolkit.HighPerformance также есть тип struct, или вы можете создать свой собственный (вероятно, class будет быстрее, чем flags, как в @Enigmativity), чтобы позволить вам обрабатывать 1D-массив как 2Д. Возможно, вам все равно придется писать код осторожно, чтобы избежать множества ненужных проверок границ.

Другие вопросы по теме