Эффективность создания списка из массива - PullRequest
0 голосов
/ 24 января 2019

Мне нужно создать список, начиная с уже созданного ранее массива, и он будет преобразован только в список. Таким образом, я мог бы использовать массив в списке, не создавая копию, но конструктор делает копию . Я даже могу понять мотивацию для этого. Однако есть случаи, когда я могу гарантировать, что массив не имеет и не будет ссылаться на него, кроме того, где он был создан.

Есть ли способ сделать эту конструкцию более эффективной и использовать массив внутри списка? Я знаю, что это может привести к неправильному использованию.

Самый очевидный пример для этого - получить результат string.Split(). Если вам нужен список, ваш единственный очевидный выход - сделать это преобразование. На данный момент я не рассматриваю возможность написания метода для непосредственного разделения на список.

Ответы [ 2 ]

0 голосов
/ 24 января 2019

Если вам не нужен List<T>, вы можете создать новый класс, который реализует IList<T> и не делает копию.

0 голосов
/ 24 января 2019

Насколько я знаю, официального способа сделать это не существует, но все еще возможно использовать System.Reflection.Посмотрев на исходный код List<T>, .NET Framework 4.7.2 , можно выделить два важных свойства _items и _size.Существует также _version, но он меняется только при изменении List<T>.Модификации: Add, AddRange, Remove и т. Д., А также Reverse и Sort.Итак, давайте предположим, что это та же самая операция, что и при создании списка из IEnumerable<T>, где _version остается равным нулю.

public static class ListExtensions
{
    public static void SetUnderlyingArray<T>(this List<T> list, T[] array)
    {
        lock (list)
        {
            SetInternalArray(list, array);
            SetInternalArraySize(list, array.Length);
        }
    }

    private static void SetInternalArraySize<T>(this List<T> list, int size)
    {
        var prop = list.GetType().GetField(
            "_size", 
            BindingFlags.NonPublic | BindingFlags.Instance);
        prop.SetValue(list, size);
    }

    private static void SetInternalArray<T>(this List<T> list, T[] array)
    {
        var prop = list.GetType().GetField(
            "_items",
            BindingFlags.NonPublic | BindingFlags.Instance);
        prop.SetValue(list, array);
    }
}

, а затем задаем базовый массив

int[] array = Enumerable.Repeat(1, 1000000).ToArray();
List<int> list = new List<int>();

list.SetUnderlyingArray(array);

Примечание Это решение сильно зависит от деталей реализации и может быть неправильным, если что-то изменится во внутренних элементах List<T>, но оно дает представление о том, как это можно сделать.

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