C# 扩展方法未返回正确的集合
我使用的是一个扩展方法,它洗牌一个通用列表。这很有效C# 扩展方法未返回正确的集合,c#,extension-methods,C#,Extension Methods,我使用的是一个扩展方法,它洗牌一个通用列表。这很有效 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]
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;
}
}
publicstaticvoidshuffle(此IList列表)
{
RNGCryptoServiceProvider=新的RNGCryptoServiceProvider();
int n=list.Count;
而(n>1)
{
字节[]框=新字节[1];
do provider.GetBytes(框);
而(!(框[0]
我正在尝试创建另一个扩展方法,该方法将使用Shuffle(),但将根据定义的组大小对列表中的项进行分组洗牌。调试扩展方法时,此方法似乎有效,但调用代码中的源列表在扩展调用后仍包含原始列表:
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;
}
public static void GroupRandomize(此IList sourceList,int groupSize)
{
List shuffledList=新列表();
列表模板列表=新建列表();
int addCounter=0;
for(int i=0;i
如何确保无序列表正确存储到源列表中?源列表实际上是一个局部变量。 最好
返回shuffedList代码>
var newList = caller.GroupRandomize<T>(5) ;
var newList=caller.GroupRandomize(5);
除非您使用的是ref
参数,否则这不会起任何作用。您可以更改方法,使其直接修改sourceList:
for(int i = 0; i < sourceList.Length; i++)
sourceList[i] = shuffledList[i];
。。。你会说:
var list = GetList().Shuffle();
将其设置为常规方法而不是扩展,以便通过引用传递:
public static void GroupRandomize<T>(ref IList<T> sourceList, int groupSize) {
// ... stuff
sourceList = shuffledList;
}
publicstaticvoidgrouprandomize(参考IList sourceList,int groupSize){
//…东西
sourceList=shuffledList;
}
或者,如果不想更改方法的标题,可以执行以下操作:
sourceList.Clear();
sourceList.AddRange( shuffledList );
编辑:
如所述,AddRange
方法在IList
界面中不可用
已经提出了一个实现AddRange
将要做的事情,因此我将通过指向另一个实现AddRange
作为IList
的扩展方法来改进他的答案,同意,我通常会尽量避免在扩展方法中修改扩展对象的值。对于带有Microsoft NuGet软件包的.NET 4.5,您可以通过选择一个来更好地表达契约。第一个示例修改列表的内容。第二个示例不修改sourceList的内容。您“尝试”将sourceList指向的内容替换为shuffledList的赋值,但除非您使用ref
,否则此更改仅为本地更改。执行sourceList=shuffledList
操作时,您将本地sourceList
变量赋值给shuffledList
引用的对象,而不更改原始列表。这是相关的:原因与扩展方法无关。您正在修改一个参数,这对我来说是一个严重的警告(除了在方法的顶部是最琐碎的,注释很好的情况)。这是可行的,但是我会考虑通过引用传递列表,而不是仅仅返回结果列表是一个糟糕的决定。AWWW,什么可能出错?出于好奇,为什么?确实,将引用传递回去同样容易,但是您知道传递ref可能导致的问题吗?我已经读了一些关于函数式编程的书,它的优点之一似乎是不可变的,并且没有副作用。听起来不错。如果你有一个域a,它总是映射到一个新的范围B。你不改变域a本身。但是没有什么能阻止你通过引用course@FrancineDeGroodTaylor这不是一个好习惯。对象往往会被传递很多次,如果你在不需要的时候开始通过引用传递东西,你会很快陷入一个非常不稳定的局面,很多不同的方法都共享一个特定引用的同一个实例,一个看似无关紧要的赋值可能会导致各种各样的错误(很难调试)疯狂别处。AddRange()方法对IListoops不可用,我没有注意到IList
前面的I
。你是对的。我将改变我的答案以反映这一点。谢谢
public static void GroupRandomize<T>(ref IList<T> sourceList, int groupSize) {
// ... stuff
sourceList = shuffledList;
}
sourceList.Clear();
sourceList.AddRange( shuffledList );