无法将IList转换为List
本文关键字:List 转换 IList | 更新日期: 2023-09-27 18:13:53
我找到了这个方法来打乱列表,但我想要的是它返回新列表,我似乎不知道如何做到这一点。
以下是我尝试的
public static class Lists {
private static System.Random rng = new System.Random();
public static List<T> Shuffle<T>(this IList<T> list) {
int n = list.Count;
while(n > 1) {
n--;
int k = rng.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
return list;
}
}
它所说的是:
无法将
IList
转换为List
我想要的是该方法返回新的Shuffled
列表,但我无法让它返回列表。如何做到这一点?
IList
不一定是List
。您的方法返回一个List
,但被传递了一个IList
:
public static List<T> Shuffle<T>(this IList<T> list) {
int n = list.Count;
while(n > 1) {
n--;
int k = rng.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
return list; //Still an IList!
}
最简单/最好的解决方案是只返回IList<T>
而不是List<T>
。
public static IList<T> Shuffle<T>(this IList<T> list) {
如果确实需要一个实际列表,请调用ToList
:
return list.ToList(); //Now its a list
当然,这会比必要的次数多枚举一次您的集合。
无法将列表转换为IList
这是因为你有一个IList<T>
,而你要返回一个List<T>
。您可以强制转换return (List<T>)list;
,但如果用另一个IList<T>
调用它,则此操作将失败。
在此之前,如果IList<T>
是只读的,它也会失败。
然而,
我想要的是它返回新的列表
这里没有新的列表。但我们很容易做到这一点:
public static List<T> Shuffle<T>(this IList<T> source) {
List<T> list = new List<T>(source);
有了这个改变,它现在创建了一个新的列表,并在返回之前对其进行洗牌
但是等等,为什么要将我们自己限制为IList<T>
作为输入呢?我们可以从任何IEnumerable<T>
创建一个新列表,为什么不这样做呢?
public static List<T> Shuffle<T>(this IEnumerable<T> source) {
List<T> list = new List<T>(source);
尽管如此,Random
在非单线程代码中以非线程安全的方式使用还是有缺陷的。也很容易更改,删除静态Random
并具有:
public static List<T> Shuffle<T>(this IEnumerable<T> source) {
List<T> list = new List<T>(source);
Random rng = new System.Random();
现在它不会出错,根据需要返回一个新的List,接受更广泛的输入,并且是线程安全的。
首先,任何List
都会自动成为IList
。List
必须实现在IList
接口上定义的方法,因此根据定义,它是IList
。
但您的代码被定义为接收IList
作为输入。这意味着您可以向它传递任何实现IList
接口的东西。因此,您可以向它传递List
、Dictionary
、ComboBoxListItems集合、SortedList
或任何实现IList
的集合类型对象。因为您"试图"在未传递List
的情况下操作并返回List
,所以编译器会查看它是否可以将传递的内容转换为List
,然后抱怨它不能。实现IList
的大多数对象都无法自动转换为List。
您的代码令人困惑,因为您传递的输入参数是IList
,但名称为list。你应该解决这个问题。如果你想返回一个List
,你需要从传入的任何集合类型在方法中创建一个。这就是.ToList()
的作用。
public static class Lists {
private static System.Random rng = new System.Random();
public static List<T> Shuffle<T>(this IList<T> iList) {
var list = iList.ToList();
int n = list .Count;
while(n > 1) {
n--;
int k = rng.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
return list;
}
}
但更好的是,您可能应该将输入参数键入为IEnumerable<T>
,而不是IList<T>
。您可以对任何枚举执行ToList((,因此这允许您的方法用于更广泛的潜在类型。
public static class Lists {
private static System.Random rng = new System.Random();
public static List<T> Shuffle<T>(this IEnumerable<T> tEnumeration) {
var list = tEnumeration.ToList();
int n = list .Count;
while(n > 1) {
n--;
int k = rng.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
return list;
}
}
public static class Lists
{
public static IList<T> Shuffle<T>(this IList<T> list)
{
Random rng = new Random();
int n = list.Count;
while (n > 1)
{
n--;
int k = rng.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
return list;
}
}
- 我改为
IList
作为返回类型 - 我已经将
Random
实例移动到方法内部。这一切都与范围有关,除非另一种方法碰巧也需要获得随机数,否则不需要在方法之外使用它 - 将左大括号移到新行上。这不是Java
我想要的是该方法返回新的Shuffled列表,但我无法让它返回列表。如何做到这一点?
这不是您的代码所做的。您的代码将列表打乱;它不会创建一个新的。
你可以返回这样的新列表:
public static List<T> Shuffle<T>(this IList<T> list) {
return list.OrderBy(x => rng.Next()).ToList();
}
如果您确实想在适当的位置打乱列表,那么可能应该为参数和返回类型使用相同的类型。在您的情况下,由于您没有使用任何特定于List
的东西,您可能应该使用IList
:
// Notice the I
public static IList<T> Shuffle<T>(this IList<T> list) {
// your code
}