Это означает, что вы пытаетесь манипулировать тем, что имеет ссылку, но еще не инициализировано. Первое, что нужно сделать, это проверить каждый созданный экземпляр. Используйте контрольные точки, часы, проверяйте свои значения varibale. Следить за трассировкой стека и искать точные строки и столбцы, которые создают проблему
Для примитивных типов (включая байты) используйте System.Buffer.BlockCopy
вместо System.Array.Copy
. Это быстрее.
Я назначил каждый из предложенных методов в цикле, выполненном 1 миллион раз, используя 3 массива по 10 байт каждый. Вот результаты:
System.Array.Copy
- 0.2187556 секунд System.Buffer.BlockCopy
- 0.1406286 секунд Я увеличил размер каждого массива до 100 элементов и повторно запустить тест:
System.Array.Copy
- 0.2812554 секунд System.Buffer.BlockCopy
- 0.2500048 секунд Я увеличил размер каждого массива до 1000 элементов и повторного запуска теста:
System.Array.Copy
- 1.0781457 секунд System.Buffer.BlockCopy
- 1.0156445 секунд Наконец, я увеличил размер каждого массива до 1 миллиона элементов и перезапустил тест, выполнив каждый цикл только 4000 раз:
System.Array.Copy
- 13.4533833 секунд System.Buffer.BlockCopy
- 13.1096267 секунд Итак, если вам нужен новый массив байтов, используйте
byte[] rv = new byte[a1.Length + a2.Length + a3.Length];
System.Buffer.BlockCopy(a1, 0, rv, 0, a1.Length);
System.Buffer.BlockCopy(a2, 0, rv, a1.Length, a2.Length);
System.Buffer.BlockCopy(a3, 0, rv, a1.Length + a2.Length, a3.Length);
Но, если вы может использовать IEnumerable<byte>
, DEFINITELY предпочитает метод Concat & lt;> LINQ. Это немного медленнее, чем оператор C # yield, но является более кратким и более элегантным.
IEnumerable<byte> rv = a1.Concat(a2).Concat(a3);
Если у вас есть произвольное количество массивов и вы используете .NET 3.5, вы можете сделать System.Buffer.BlockCopy
Решение более общее:
private byte[] Combine(params byte[][] arrays)
{
byte[] rv = new byte[arrays.Sum(a => a.Length)];
int offset = 0;
foreach (byte[] array in arrays) {
System.Buffer.BlockCopy(array, 0, rv, offset, array.Length);
offset += array.Length;
}
return rv;
}
* Примечание. В приведенном выше блоке вы должны добавить следующее пространство имен вверху, чтобы оно работало.
using System.Linq;
К Jon Skeet's (байтовый массив против IEnumerable & lt; byte>), я повторно запустил последний тест времени (1 миллион элементов, 4000 итераций), добавив цикл, который выполняет итерацию по всему массиву с каждым проходом:
System.Array.Copy
- 78.20550510 секунд System.Buffer.BlockCopy
- 77.89261900 секунд Суть в том, что ОЧЕНЬ важно, чтобы понять эффективность как креацио n и использование результирующей структуры данных. Простое сосредоточение на эффективности создания может не учитывать неэффективность, связанную с использованием. Кудос, Джон.
На самом деле я столкнулся с некоторыми проблемами с использованием Concat ... (с массивами в 10 миллионов, он фактически разбился).
Я нашел следующее, чтобы быть простым, легким и работать достаточно хорошо, без сбой на мне, и он работает для ЛЮБОГО числа массивов (не только трех) (он использует LINQ):
public static byte[] ConcatByteArrays(params byte[][] arrays)
{
return arrays.SelectMany(x => x).ToArray();
}
Класс memystream делает эту работу очень красиво для меня. Я не мог заставить класс буфера работать так же быстро, как memystream.
using (MemoryStream ms = new MemoryStream())
{
ms.Write(BitConverter.GetBytes(22),0,4);
ms.Write(BitConverter.GetBytes(44),0,4);
ms.ToArray();
}
Все, что вам нужно, чтобы передать список байт-массивов, и эта функция вернет вам массив байтов (объединенный). Это лучшее решение, о котором я думаю:).
public static byte[] CombineMultipleByteArrays(List<byte[]> lstByteArray)
{
using (var ms = new MemoryStream())
{
using (var doc = new iTextSharp.text.Document())
{
using (var copy = new PdfSmartCopy(doc, ms))
{
doc.Open();
foreach (var p in lstByteArray)
{
using (var reader = new PdfReader(p))
{
copy.AddDocument(reader);
}
}
doc.Close();
}
}
return ms.ToArray();
}
}
Может использовать generics для объединения массивов. Следующий код можно легко расширить до трех массивов. Таким образом, вам не нужно дублировать код для разных типов массивов. Некоторые из приведенных выше ответов кажутся мне слишком сложными.
private static T[] CombineTwoArrays<T>(T[] a1, T[] a2)
{
T[] arrayCombined = new T[a1.Length + a2.Length];
Array.Copy(a1, 0, arrayCombined, 0, a1.Length);
Array.Copy(a2, 0, arrayCombined, a1.Length, a2.Length);
return arrayCombined;
}
public static bool MyConcat<T>(ref T[] base_arr, ref T[] add_arr)
{
try
{
int base_size = base_arr.Length;
int size_T = System.Runtime.InteropServices.Marshal.SizeOf(base_arr[0]);
Array.Resize(ref base_arr, base_size + add_arr.Length);
Buffer.BlockCopy(add_arr, 0, base_arr, base_size * size_T, add_arr.Length * size_T);
}
catch (IndexOutOfRangeException ioor)
{
MessageBox.Show(ioor.Message);
return false;
}
return true;
}
Если вам просто нужен новый массив байтов, используйте следующее:
byte[] Combine(byte[] a1, byte[] a2, byte[] a3)
{
byte[] ret = new byte[a1.Length + a2.Length + a3.Length];
Array.Copy(a1, 0, ret, 0, a1.Length);
Array.Copy(a2, 0, ret, a1.Length, a2.Length);
Array.Copy(a3, 0, ret, a1.Length + a2.Length, a3.Length);
return ret;
}
В качестве альтернативы, если вам нужен только один IEnumerable, подумайте о том, как использовать оператор yield C # 2.0:
IEnumerable<byte> Combine(byte[] a1, byte[] a2, byte[] a3)
{
foreach (byte b in a1)
yield return b;
foreach (byte b in a2)
yield return b;
foreach (byte b in a3)
yield return b;
}
Многие из ответов, как мне кажется, игнорируют указанные требования:
Эти два вместе исключают последовательность байтов LINQ - что-либо с yield
будет делать невозможным получение окончательного размера без итерации по всей последовательности.
Если это не требования real , конечно, LINQ может быть идеальным решением (или реализацией IList<T>
). Тем не менее, я предполагаю, что Superdumbell знает, чего он хочет.
(EDIT: У меня была другая мысль: существует большая смысловая разница между копированием массивов и ленивым чтением. происходит, если вы измените данные в одном из массивов «источник» после вызова метода Combine
(или любого другого), но перед использованием результата - с ленивой оценкой это изменение будет видимым. С немедленной копией он не будет Различные ситуации потребуют различного поведения - просто что-то, о чем нужно знать.)
Вот мои предложенные методы, которые очень похожи на те, что содержатся в некоторых других ответах, конечно:)
public static byte[] Combine(byte[] first, byte[] second)
{
byte[] ret = new byte[first.Length + second.Length];
Buffer.BlockCopy(first, 0, ret, 0, first.Length);
Buffer.BlockCopy(second, 0, ret, first.Length, second.Length);
return ret;
}
public static byte[] Combine(byte[] first, byte[] second, byte[] third)
{
byte[] ret = new byte[first.Length + second.Length + third.Length];
Buffer.BlockCopy(first, 0, ret, 0, first.Length);
Buffer.BlockCopy(second, 0, ret, first.Length, second.Length);
Buffer.BlockCopy(third, 0, ret, first.Length + second.Length,
third.Length);
return ret;
}
public static byte[] Combine(params byte[][] arrays)
{
byte[] ret = new byte[arrays.Sum(x => x.Length)];
int offset = 0;
foreach (byte[] data in arrays)
{
Buffer.BlockCopy(data, 0, ret, offset, data.Length);
offset += data.Length;
}
return ret;
}
Конечно, версия «params» требует создания массива массивов байтов, что приводит к дополнительной неэффективности.
Конкат - это правильный ответ, но по какой-то причине наибольшее количество голосов получает зарубленная вещь. Если вам нравится этот ответ, возможно, вам понадобится еще более общее решение:
IEnumerable<byte> Combine(params byte[][] arrays)
{
foreach (byte[] a in arrays)
foreach (byte b in a)
yield return b;
}
, который позволит вам делать такие вещи, как:
byte[] c = Combine(new byte[] { 0, 1, 2 }, new byte[] { 3, 4, 5 }).ToArray();
Я сделал пример Мэтта LINQ еще одним шагом для обеспечения чистоты кода:
byte[] rv = a1.Concat(a2).Concat(a3).ToArray();
В моем случае массивы небольшие, поэтому меня не касается производительности.
Вот обобщение ответа, предоставленного @Jon Skeet. Это в основном то же самое, только он может использоваться для любого типа массива, а не только для байтов:
public static T[] Combine<T>(T[] first, T[] second)
{
T[] ret = new T[first.Length + second.Length];
Buffer.BlockCopy(first, 0, ret, 0, first.Length);
Buffer.BlockCopy(second, 0, ret, first.Length, second.Length);
return ret;
}
public static T[] Combine<T>(T[] first, T[] second, T[] third)
{
T[] ret = new T[first.Length + second.Length + third.Length];
Buffer.BlockCopy(first, 0, ret, 0, first.Length);
Buffer.BlockCopy(second, 0, ret, first.Length, second.Length);
Buffer.BlockCopy(third, 0, ret, first.Length + second.Length,
third.Length);
return ret;
}
public static T[] Combine<T>(params T[][] arrays)
{
T[] ret = new T[arrays.Sum(x => x.Length)];
int offset = 0;
foreach (T[] data in arrays)
{
Buffer.BlockCopy(data, 0, ret, offset, data.Length);
offset += data.Length;
}
return ret;
}
public static byte[] Concat(params byte[][] arrays) {
using (var mem = new MemoryStream(arrays.Sum(a => a.Length))) {
foreach (var array in arrays) {
mem.Write(array, 0, array.Length);
}
return mem.ToArray();
}
}