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





Используйте List <T>. Он будет динамически изменяться по мере необходимости.
@ user7116 никогда? почему и причины?
Вместо этого используйте ArrayLists или Generics
Точнее, используйте List <T>. В .NET существует множество универсальных классов или функций, размер которых нельзя изменять. ;)
Я бы держался подальше от ArrayLists. Помимо того, что их сложнее использовать, Microsoft заявила, что они не будут доступны на новых платформах, таких как Silverlight.
Silverlight больше нет @JonathanAllen. собирается исчезнуть.
Вам действительно не следует использовать ReDim, это может быть очень дорого. Я предпочитаю List (Of T), но в этой области есть много вариантов.
Тем не менее, у вас возник вопрос, и вот ваш ответ.
x = (int[]) Utils.CopyArray((Array) x, new int[10]);
Как вы думаете, как List <T> справляется, когда ему нужно изменить размер своего внутреннего буфера? По сути, он делает то же самое, что и ReDim Preserve ... Как вы думаете, почему ReDim стоит дорого, но не List <T>? (List <T>, безусловно, более удобен во многих отношениях, но им в основном нужно делать то же самое ...)
Джон, разве ReDim Preserve не добавляет то, что нам нужно в то время, когда мы просим, а List <T> удваивает размер, поскольку .net считает, что это необходимо? Я бы предположил, что это отслеживается и удваивается, когда фреймворк считает, что это оптимально и, следовательно, менее затратно? Спасибо!
Мы должны поместить вещи в контекст, чтобы увидеть различия между ReDim Preserve (на самом деле Array.Copy) и List <T>. Если вы изменяете размер внутри цикла, после нескольких итераций List <T> выделяет меньше памяти, чем ReDim Preserve. Это происходит потому, что, хотя новый массив создается для каждой итерации цикла с помощью Redim Preserve, с помощью List <T> новые массивы создаются только тогда, когда в текущем не хватает места для нового элемента.
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 работает с многомерными массивами. Не уверен в части, отсчитываемой от нуля
тоже стоит отметить .. и я не знаю, так ли это с редимом. Но стоит также отметить, что с C# Array.Resize заставит переменную указывать на новый массив (как можно увидеть с помощью Object.ReferenceEquals (..). Итак, y и x теперь указывают на два разных массива .. y больше не псевдоним для x .. И изменение x [0] больше не изменит y [0]. и теперь у вас есть два массива, а не один.
@barlop: Да, именно это демонстрирует пример ... и почему я написал: «Эквивалент« Redim Preserve »- это Array.Resize <T> - но вы должны знать, что если есть другие ссылки на исходный массив , они вообще не будут изменены ".
Я всегда думал (предполагал), что если бы новый размер был меньше, он бы повторно использовал ту же самую память и просто «обрезал» излишки. Справочный источник ясно показывает, что каждый раз вы будете получать новый массив.
@ChadSchouggins: Было бы хорошо, если бы ...? Суперэффективный термоусадочный массив.
@JaredPar: с этим можно бороться некоторыми способами, умножив многомерный массив на одно измерение, а затем увеличив размер массива на порядки. Я знаю, что это не настоящее решение, но возможность.
Я не мог не заметить, что никто из приведенных выше ответов приближается к концепции многомерных массивов. При этом вот пример. Рассматриваемый массив предопределен как 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;
}
Я думаю, что другая сторона скажет: «Я был шокирован, узнав, что VB поддерживает массивы с динамическим размером».