如何在C#中将IList<T>转换为List<T>性能好且简洁?

How to convert IList<T> to List<T> in C# with good performance and concisely?

尽管这些问题的答案中有一些信息:Cast IList to List and Performance impact when calling ToList()它们没有回答我的具体问题。我有一个 class 是 List 的包装器。此 class 旨在通过 WCF 服务发送并实现一些附加功能。

[DataContract]
public class DataContractList<T> : IList<T>
{
    [DataMember]
    protected readonly List<T> InnerList;

    public DataContractList()
    {
        InnerList = new List<T>();
    }

    public DataContractList(IList<T> items)
    {
        InnerList = items as List<T> ?? items.ToList(); //Question is about this line.
    }
}

所以有一个接受IList<T>接口的构造函数(为了鼓励编程接口)。我需要将此 IList<T> 接口转换为 List<T> class。我可以使用 .ToList() 扩展方法,它通过将 IEnumrable "this" 参数传递给它的构造函数在内部创建 List<T> 的新实例(参见 here)。通用 List<T> 构造函数只是迭代这个可枚举的。因此,如果没有必要,我想阻止此迭代(以防内部项参数已经是 List<T>)。那么,这样做是否是最佳方式(就性能和可读性而言):InnerList = items as List<T> ?? items.ToList();?如果否,请详细说明更好的方法和原因。

恕我直言,如果您从 IList<T> 继承,然后强制使用 List<T>,它就达不到目的了,不是吗?

使用接口的想法是支持不同的 classes,其中只有共享功能很重要。

在你的例子中,你的 DataContractList class 接受任何实现 IList<T> 的 class,但是如果我创建一个实现 [=11] 的 class =] 但不能转换为 List<T>,我会得到一个 运行 时间错误,不是吗?

如果您的 DataContractList class 只能支持该接口的实现,我建议您从 List<T> 继承。

或者,如果您的 DataContractList class 确实可以支持 IList<T> 的任何实现,则将其更改为:

[DataContract]
public class DataContractList<T> : IList<T>
{
    [DataMember]
    protected readonly IList<T> InnerList;

    public DataContractList()
    {
        InnerList = new List<T>();
    }

    public DataContractList(IList<T> items)
    {
        InnerList = items;
    }
}

尽量避免迭代列表是个好主意,但还有更多需要考虑的地方。

您已保护 InnerList 属性不被 public 访问,如果您只是将列表分配给 属性 则该努力毫无意义。如果我将列表发送到构造函数并保留对该列表的引用,那么我将引用 class 内部使用的列表:

List<sting> list = new List<string>();
var dc = new DataContractList(list);

// now I can manipulate the internal list:
list.Add("Woaaah! Where did that come from?");

为了将内部列表保留在内部,即使输入是一个列表,您也总是会创建一个新列表:

public DataContractList(IList<T> items)
{
    InnerList = new List<T>(items);
}

您注意到 WCF 默认序列化不适用于任意 IList<T> 实现。不错。

然后您决定通过强制使用 List<T> 来解决该问题。不太好。

如果默认序列化不能满足您的要求,请不要使用它。使用自定义序列化。如果您知道那是您想要做的,您可以逐项进行 class 序列化,即使内部容器不知道它。

并回答您可能的后续问题:快速搜索显示了如何在 Stack Overflow 上执行此操作的基本方法:How to use Custom Serialization or Deserialization in WCF to force a new instance on every property of a datacontact ?

只是为了完成古法的回答。正如您提到的,使用

InnerList = new List<T>(items);

InnerList = items.ToList();

基本上是一样的,所以从可读性的角度我更喜欢后者

然而,下面的

Generic List constructor just iterates through this enumberable.

不正确,正如您在此处看到的那样 http://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,d2ac2c19c9cf1d44, which in turn is using http://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,0c418e0fac68ada2 当参数的类型为 List<T> 时。很快,您不应该担心性能。