如何在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>
时。很快,您不应该担心性能。
尽管这些问题的答案中有一些信息: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>
时。很快,您不应该担心性能。