Redim Preserve на C#?

Сегодня я был шокирован, узнав, что C# не поддерживает массивы динамического размера. Как же тогда разработчик VB.NET, привыкший использовать ReDim Preserve, справляется с этим на C#?

В начале функции я не уверен в верхней границе массива. Это зависит от строк, возвращаемых из базы данных.

Я думаю, что другая сторона скажет: «Я был шокирован, узнав, что VB поддерживает массивы с динамическим размером».

user7116 30.11.2008 22:00

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

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

Ответы 7

Используйте List <T>. Он будет динамически изменяться по мере необходимости.

@ user7116 никогда? почему и причины?

Kiquenet 09.11.2017 00:48
Ответ принят как подходящий

Вместо этого используйте ArrayLists или Generics

Точнее, используйте List <T>. В .NET существует множество универсальных классов или функций, размер которых нельзя изменять. ;)

jalf 29.11.2008 22:52

Я бы держался подальше от ArrayLists. Помимо того, что их сложнее использовать, Microsoft заявила, что они не будут доступны на новых платформах, таких как Silverlight.

Jonathan Allen 29.11.2008 23:00

Silverlight больше нет @JonathanAllen. собирается исчезнуть.

Malachi 05.02.2014 23:02

Точный эквивалент ReDim Preserve - ответил на @JonSkeet.

QuantumHive 05.09.2016 13:28

Вам действительно не следует использовать ReDim, это может быть очень дорого. Я предпочитаю List (Of T), но в этой области есть много вариантов.

Тем не менее, у вас возник вопрос, и вот ваш ответ.

x = (int[]) Utils.CopyArray((Array) x, new int[10]);

Как вы думаете, как List <T> справляется, когда ему нужно изменить размер своего внутреннего буфера? По сути, он делает то же самое, что и ReDim Preserve ... Как вы думаете, почему ReDim стоит дорого, но не List <T>? (List <T>, безусловно, более удобен во многих отношениях, но им в основном нужно делать то же самое ...)

Jon Skeet 29.11.2008 23:17

Джон, разве ReDim Preserve не добавляет то, что нам нужно в то время, когда мы просим, ​​а List <T> удваивает размер, поскольку .net считает, что это необходимо? Я бы предположил, что это отслеживается и удваивается, когда фреймворк считает, что это оптимально и, следовательно, менее затратно? Спасибо!

user10178 30.11.2008 22:36

Мы должны поместить вещи в контекст, чтобы увидеть различия между ReDim Preserve (на самом деле Array.Copy) и List <T>. Если вы изменяете размер внутри цикла, после нескольких итераций List <T> выделяет меньше памяти, чем ReDim Preserve. Это происходит потому, что, хотя новый массив создается для каждой итерации цикла с помощью Redim Preserve, с помощью List <T> новые массивы создаются только тогда, когда в текущем не хватает места для нового элемента.

Alfred Myers 17.08.2009 15:54

VB.NET также не имеет представления о массивах с динамическим размером - CLR не поддерживает его.

Эквивалент «Redim Preserve» - Array.Resize<T> - но вы должен должны знать, что если есть другие ссылки на исходный массив, они вообще не будут изменены. Например:

using System;

class Foo
{
    static void Main()
    {
        string[] x = new string[10];
        string[] y = x;

        Array.Resize(ref x, 20);
        Console.WriteLine(x.Length); // Prints out 20
        Console.WriteLine(y.Length); // Still prints out 10
    }
}

Доказательство того, что это эквивалент Redim Preserve:

Imports System

Class Foo
    Shared Sub Main()
        Dim x(9) as String
        Dim y as String() = x

        Redim Preserve x(19)
        Console.WriteLine(x.Length)
        Console.WriteLine(y.Length)
    End Sub
End Class

Две программы эквивалентны.

Если вам действительно нужна коллекция с динамическим размером, вам следует использовать List<T> (или что-то подобное). При прямом использовании массивов возникают различные проблемы - подробности см. В Сообщение в блоге Эрика Липперта. Это не значит, что вы всегда должны избегать их ни в коем случае - но вам нужно знать, с чем вы имеете дело.

Есть одно различие между техниками. Array.Resize работает только с одномерными массивами с отсчетом от нуля. Redim работает с многомерными массивами. Не уверен в части, отсчитываемой от нуля

JaredPar 30.11.2008 10:44

тоже стоит отметить .. и я не знаю, так ли это с редимом. Но стоит также отметить, что с C# Array.Resize заставит переменную указывать на новый массив (как можно увидеть с помощью Object.ReferenceEquals (..). Итак, y и x теперь указывают на два разных массива .. y больше не псевдоним для x .. И изменение x [0] больше не изменит y [0]. и теперь у вас есть два массива, а не один.

barlop 01.03.2016 21:20

@barlop: Да, именно это демонстрирует пример ... и почему я написал: «Эквивалент« Redim Preserve »- это Array.Resize <T> - но вы должны знать, что если есть другие ссылки на исходный массив , они вообще не будут изменены ".

Jon Skeet 01.03.2016 21:22

Я всегда думал (предполагал), что если бы новый размер был меньше, он бы повторно использовал ту же самую память и просто «обрезал» излишки. Справочный источник ясно показывает, что каждый раз вы будете получать новый массив.

Chad Schouggins 19.05.2016 02:22

@ChadSchouggins: Было бы хорошо, если бы ...? Суперэффективный термоусадочный массив.

Paul 07.09.2017 14:00

@JaredPar: с этим можно бороться некоторыми способами, умножив многомерный массив на одно измерение, а затем увеличив размер массива на порядки. Я знаю, что это не настоящее решение, но возможность.

Paul 07.09.2017 14:03

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

int[,] temp = new int[newRows, newCols];
int minRows = Math.Min(newRows, x.GetUpperBound(0) + 1);
int minCols = Math.Min(newCols, x.GetUpperBound(1) + 1);
for (int i = 0; i < minRows ; ++i)
     for (int j = 0; j < minCols; ++j)
         temp[i, j] = x[i, j];
x = temp;

Просто для удовольствия, вот один из способов использования дженериков, чтобы изменить / расширить одномерный массив (добавить еще одну «строку»):

static T[] Redim<T>(T[] arr, bool preserved)
{
    int arrLength = arr.Length;
    T[] arrRedimed = new T[arrLength + 1];
    if (preserved)
    {
        for (int i = 0; i < arrLength; i++)
        {
            arrRedimed[i] = arr[i];
        }
    }
    return arrRedimed;
}

И еще один для добавления n строк (хотя это не мешает пользователю уменьшить размер массива, что вызовет ошибку в цикле for):

static T[] Redim<T>(T[] arr, bool preserved, int nbRows)
{
    T[] arrRedimed = new T[nbRows];
    if (preserved)
    {
        for (int i = 0; i < arr.Length; i++)
        {
            arrRedimed[i] = arr[i];
        }
    }
    return arrRedimed;
}

Я уверен, что вы уловили идею.

Для многомерного массива (двух измерений) вот одна возможность:

static T[,] Redim<T>(T[,] arr, bool preserved)
{
    int Ubound0 = arr.GetUpperBound(0);
    int Ubound1 = arr.GetUpperBound(1);
    T[,] arrRedimed = new T[Ubound0 + 1, Ubound1];
    if (preserved)
    {
        for (int j = 0; j < Ubound1; j++)
        {
            for (int i = 0; i < Ubound0; i++)
            {
                arrRedimed[i, j] = arr[i, j];
            }
        }
    }
    return arrRedimed;
}

В вашей программе используйте это с указанным типом или даже без него, компилятор распознает его:

int[] myArr = new int[10];
myArr = Redim<int>(myArr, true);

или же

int[] myArr = new int[10];
myArr = Redim(myArr, true);

Не уверен, что все это действительно актуально. = D Не стесняйтесь исправлять меня или улучшать мой код. ;)

Несмотря на то, что это было давно, это может помочь кому-то, кто ищет простое решение - я нашел кое-что отличное на другом форуме:

//from Applied Microsoft.NET framework Programming - Jeffrey Richter
public static Array RedimPreserve(Array origArray, Int32 desiredSize)
        {
            System.Type t = origArray.GetType().GetElementType();
            Array newArray = Array.CreateInstance(t, desiredSize);
            Array.Copy(origArray, 0, newArray, 0, Math.Min(origArray.Length, desiredSize));
            return newArray;
        }

Источник: https://social.msdn.microsoft.com/Forums/en-US/6759816b-d525-4752-a3c8-9eb5f4a5b194/redim-in-c?forum=csharplanguage

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