Метод расширения для ICollection‹T› не меняет список вызовов?

Я хочу создать метод расширения, который запускается в списке и принимает другой список:

public static void Charge<T, S>(this ICollection<T> targetList, ICollection<S> sourceList) where T : class, new()
        {
            if (targetList == null || sourceList == null)
                throw new NullReferenceException();
            targetList = new List<T>();
            foreach (var item in sourceList)
            {
                T t = new T();
                //do work on t
                targetList.Add(t);
            }

        }

однако, когда я называю это так:

var targetList = new List<Item>();
targetList.Charge(sourceList);

targetList не меняется (количество предметов = 0)


person mshwf    schedule 25.09.2017    source источник
comment
Удалить targetList = new List<T>();   -  person L.B    schedule 25.09.2017
comment
Почему вы делаете targetList = new List<T>();?   -  person rbm    schedule 25.09.2017
comment
Вы не возвращаете целевой список и не обрабатываете его как ссылку.   -  person Trioj    schedule 25.09.2017
comment
Я хочу убедиться, что это пустой список   -  person mshwf    schedule 25.09.2017
comment
А как насчет ICollection.Clear()   -  person Michael    schedule 25.09.2017
comment
Если вы хотите убедиться, что он пуст, почему бы просто не удалить из него предметы?   -  person HaukurHaf    schedule 25.09.2017
comment
Что вы ожидаете получить, когда ваш метод вернет void?   -  person maccettura    schedule 25.09.2017
comment
Почему вы вообще хотите, чтобы кто-то передал пустую коллекцию? Просто не заставляйте вызывающую сторону предоставлять коллекцию для начала и просто возвращайте новую коллекцию.   -  person Servy    schedule 25.09.2017
comment
@maccettura ничего не возвращает   -  person mshwf    schedule 25.09.2017
comment
Я согласен с @Servy. Я бы даже не стал передавать список целей в качестве параметра.   -  person Trioj    schedule 25.09.2017
comment
@MohamedAhmed, значит, изменить список и ничего с ним не делать? Подумайте об этом, вы действительно думаете, что это то, чего вы хотите?   -  person maccettura    schedule 25.09.2017
comment
Разве весь этот метод не является просто сложным способом не вызывать IEnumerable‹T›.Select()?   -  person Trioj    schedule 25.09.2017


Ответы (2)


Предложенный метод мне непонятен.

Вы хотите скопировать содержимое исходного списка в целевой, но сначала хотите заменить целевой список, чтобы убедиться, что он пуст? Если вы все равно собираетесь заменить целевой список, почему бы просто не заменить его вот так?

target = source.ToList();

Кроме того, как вы предлагаете реализовать «поработать над t» в общем методе расширения, где типы S и T неизвестны? Почему бы не сделать идиоматическую вещь, например:

target = source.Select(s => Transform(s)).ToList();

Здесь мы предполагаем, что Transform — это метод, способный создавать и заполнять целевой объект из исходного объекта.

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

target.Clear();
target.AddRange(source.Select(s => Transform(s)));

И если вы действительно хотите иметь один вызов, вы можете просто обернуть любую из вышеперечисленных альтернатив, например:

public static List<TTarget> ToList<TSource, TTarget>(
    this IEnumerable<TSource> source,
    Func<TSource, TTarget> conversion)
{
    if (source == null)
        throw new ArgumentNullException(nameof(source));
    if (conversion == null)
        throw new ArgumentNullException(nameof(conversion));

    return source.Select(conversion).ToList();
}

Применение:

target = source.ToList(s => Transform(s));
person Mike Strobel    schedule 25.09.2017
comment
Re: просто вызов ToList(): насколько я понимаю, проблема в том, что исходный список OP отличается от T целевого списка. Действительно, ИМО, я не понимаю, почему весь код не выглядит примерно так: var newThings = oldThings.Select(thing => ConvertOldThingToNewThing(thing)); - person Trioj; 25.09.2017
comment
Без проблем. Честно говоря, мне потребовалось больше времени, чем хотелось бы, чтобы понять, что на самом деле это всего лишь странным образом сконструированный вызов Select() с преобразованием. - person Trioj; 25.09.2017

Вы не можете назначить новый экземпляр targetList, если вы передаете список по значению. Вы можете добавлять, удалять или изменять содержимое существующего списка, но если вы хотите назначить другой экземпляр, вам нужно добавить ключевое слово ref, чтобы разрешить назначения.

person Michael    schedule 25.09.2017
comment
Вы не можете пометить this аргумент метода расширения с помощью ref. - person user4003407; 25.09.2017
comment
Я знаю это. Но поскольку оба являются коллекциями, вы можете поменять местами аргументы public static void Charge<T, S>(this ICollection<S> sourceList, ref ICollection<T> targetList) - person Michael; 25.09.2017