-3

I want to create an extension method that runs on a List and accept another list:

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);
            }

        }

however when I call it like this:

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

the targetList doesn't change (items count = 0)

mshwf
  • 7,009
  • 12
  • 59
  • 133

2 Answers2

0

The proposed method makes no sense to me.

You want to copy the contents of the source list into the target, but you first want to replace the target list to make sure it's empty? If you're going to replace the target list anyway, why not simply replace it like so?

target = source.ToList();

Also, how do you propose to implement the "do some work on t" in a generic extension method where the types of S and T are not known? Why not do the idiomatic thing, e.g.:

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

Here, we assume Transform is a method capable of creating and populating a target object from a source object.

Or, you could avoid reallocating a new list by clearing the old one first:

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

And if you really want to have a single invocation, you could simply wrap either of the alternatives above, e.g.:

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();
}

Usage:

target = source.ToList(s => Transform(s));
Mike Strobel
  • 25,075
  • 57
  • 69
  • 1
    Re: just calling ToList(): As I understand it, the problem with that is that the OP's source list is a different T than the target list. Really, IMO, I don't see why the entire code isn't something like var newThings = oldThings.Select(thing => ConvertOldThingToNewThing(thing)); – Trioj Sep 25 '17 at 19:54
  • No worries. It honestly took me longer than I'd have liked to have just come to the realization that this is really just an weirdly-engineered Select() call with a transform. – Trioj Sep 25 '17 at 20:01
-1

You can't assign a new instance to targetList if you pass the list by value. You can add or remove or modify the content of the existing list, but if you want to assign another instance you need to add the ref keyword to allow assignments.

Michael
  • 1,931
  • 2
  • 8
  • 22
  • 3
    You can not mark `this` argument of extension method with `ref`. – user4003407 Sep 25 '17 at 19:36
  • I know that. But since both are Collections you could swap arguments `public static void Charge(this ICollection sourceList, ref ICollection targetList)` – Michael Sep 25 '17 at 19:38