简体   繁体   中英

Extension Method not Returning Correct Collection

I am using an extension method which shuffles a generic list. This works

    public static void Shuffle<T>(this IList<T> list)
  {
    RNGCryptoServiceProvider provider = new RNGCryptoServiceProvider();
    int n = list.Count;
    while (n > 1)
    {
      byte[] box = new byte[1];
      do provider.GetBytes(box);
      while (!(box[0] < n * (Byte.MaxValue / n)));
      int k = (box[0] % n);
      n--;
      T value = list[k];
      list[k] = list[n];
      list[n] = value;
    }
  }

I am trying trying to create another extension method which would utilize Shuffle(), but would shuffle the items in a list in groups based on a defined group size. This method seems to work when debugging the extension method, but the source list in the calling code still contains the original list after the extension call:

    public static void GroupRandomize<T>(this IList<T> sourceList, int groupSize)
  {
    List<T> shuffledList = new List<T>();
    List<T> tempList = new List<T>();
    int addCounter = 0;
    for (int i = 0; i < sourceList.Count; i++)
    {
      tempList.Add(sourceList[i]);
      // if we've built a full group, or we're done processing the entire list
      if ((addCounter == groupSize - 1) || (i == sourceList.Count - 1))
      {
        tempList.Shuffle();
        shuffledList.AddRange(tempList);
        tempList.Clear();
        addCounter = 0;
      }
      else
      {
        addCounter++;
      }
    }
    sourceList = shuffledList;
  }

How do I ensure the shuffled list is stored properly into the source list?

sourceList is actually a local variable. Might be better to return shuffedList;

var newList = caller.GroupRandomize<T>(5) ;
sourceList = shuffledList;

This will do nothing unless you are using a ref parameter. You could change your method so that it modifies the sourceList directly:

for(int i = 0; i < sourceList.Length; i++)
    sourceList[i] = shuffledList[i];

But I'd recommend changing your approach so that the extension methods return new, shuffled lists, leaving the original lists intact. So instead of:

var list = GetList();
list.Shuffle();

... you would say:

var list = GetList().Shuffle();

Make it a regular method instead of an extension so you can pass it in by reference:

public static void GroupRandomize<T>(ref IList<T> sourceList, int groupSize) {
    // ... stuff
    sourceList = shuffledList;
}

Or if you don't want to change the header of the method, you could do the something like:

sourceList.Clear();
sourceList.AddRange( shuffledList );

Edit:

As stated by bperniciaro , The AddRange method is not available in the IList<T> interface.

StriplingWarrior already suggested an implementation that does what AddRange would do, so instead I will just improve his answer a little by pointing to another answer , by hvostt , that implements AddRange as an extension method of IList<T> .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM