2017-02-17 15 views
0

У меня есть класс коллекции, полученный от List<T>, и вам нужно выполнить упакованный action экземпляр этой коллекции (то есть коллекция слишком велика, поэтому Я хочу разбить коллекцию на части и выполнить action на частях). Обратите внимание, что действие имеет типизированную подпись, это предопределенный метод, который ожидает коллекцию того же типа.Как получить ссылку на часть списка без создания копии в C#

Я знаю

target.addRange(source.getRange(start, packageSize); 

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

action(source.Reference(fromIndex, toIndex); 

с целью не создавать копии записей списка (я знаю, что это «только» ссылки , но все же есть копия. Есть ли способ сделать это в C#?

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

+0

Благодарим вас за отзыв. Если бы вы объяснили нисходящее движение, я мог бы принять вашу критику в следующий раз, когда я напишу вопрос. – Thomas

+0

_I знаю, что это «единственные» ссылки. Именно поэтому вы не должны беспокоиться об этом. Вы будете делать копии этих ссылок постоянно, не решайте проблем, которые у вас нет. –

+0

@HenkHolterman Спасибо за ввод. Я проверю, имеет ли это значение, используя предложения из полученных ответов. Программа будет явно работать на устройстве с ограниченным ресурсом (частота процессора и память), а не на общем ПК, поэтому я разработал привычку быть жадным с любым видом ресурсов. – Thomas

ответ

1

Просто используйте Linq:

var notAList = source.Skip(fromIndex).Take(toIndex-fromIndex); 
action(notAList); 

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

+0

Не было бы проще сделать 'source.Take (toIndex) .Skip (fromIndex)'? – overactor

+0

@overactor Мне кажется, что ваш пример недействителен. – eocron

+0

@overactor, который тоже сработает. Но теперь 'Skip' будет немного медленнее, поскольку он не может использовать источник, являющийся' List 'больше. –

1

Вы можете использовать LINQ-х Skip() и Take() для этого:

public void MyAction<T>(IEnumerable<T> range) 
{ 
    // ... 
} 

и называют

MyAction(list.Skip(fromIndex).Take(toIndex-fromIndex)); 

Обратите внимание, что эти операторы (Skip и Take) использовать отложила выполнение и оценку ленивым. Таким образом, вы действительно можете думать об этом как своего рода ссылка на диапазон в списке источников.

2

Вместо того, чтобы копировать ссылки в новый список, вы можете использовать LINQ или просто C#, чтобы получить часть из списка.

Использование Skip и Take:

var iterator = source.Skip(start).Take(end - start); 

Поскольку это IEnumerable, вы можете foreach за что внутри метода, называемого (так что вам, возможно, придется изменить метод подписи):

foreach (var x in iterator) 
{ 
    ... 
} 

Или создайте свой собственный автомат. В результате перечислимы могут быть переданы по методу тоже:

private static IEnumerable<T> Take<T>(List<T> source, int start, int end) 
{ 
    for (int i = start; i < end; i++) 
    { 
     yield return source[i]; 
    } 
} 
+0

Спасибо за ответ, но у меня создается впечатление, что оператор Linq приводит к другому типу. 'action' ожидает данного типа в качестве аргумента. – Thomas

+0

Так что же вы думаете о своем «Действии»? Я сказал, что использование 'IEnumerable ' может потребоваться изменение подписи. –

+0

класс коллекции, полученный из 'List ' Я упомянул в начале – Thomas

1

Вы можете создать свой собственный итератор:

public class MyPartListIterator: IEnumerator 
{ 
    private readonly IList list; 
    private readonly int _startIdx; 
    private readonly int _endIdx; 
    private int _current; 

    public MyIterator(IList list, int start, int end) 
    { 
     //do some validations before etc 
     this._startIdx = this._current = start; 
     this._endIdx = end; 
     this._list= list; 

    } 

    public bool MoveNext() 
    { 
     //do some checks against list was changed 

     if (this._current >= this._endIdx) return false; 
     this._current += 1; 
    } 

    public object Current => this._list[this._current]; 

    public void Reset() => this._current = this._startidx; 
} 

Затем вы можете передать экземпляр итератора вашему action.

Почему это лучше, чем Skip и Take? Он не перечисляет элементы перед началом индекса.

Вы также можете подготовить общую версию курса.

Wrtten из памяти, не проверено. Используются синтаксические сахара S # 6.0.

EDIT:

Это невозможно передать ту же ссылку на IList<T> в большом ILIst<T> и содержит только часть данных исходного списка.

0

Здесь вы можете использовать расширения, чтобы получить необходимую функциональность.

 Смежные вопросы

  • Нет связанных вопросов^_^