无法将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

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都会自动成为IListList必须实现在IList接口上定义的方法,因此根据定义,它是IList

但您的代码被定义为接收IList作为输入。这意味着您可以向它传递任何实现IList接口的东西。因此,您可以向它传递ListDictionary、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
}
相关文章: