System.Collections.Generic.List<T> 类
本文提供了此 API 参考文档的补充说明。
该 List<T> 类是类的 ArrayList 泛型等效项。 它通过使用根据需要动态增加大小的数组来实现 IList<T> 泛型接口。
可以使用或AddRange方法将项添加到 a。List<T>Add
该 List<T> 类同时使用相等比较器和排序比较器。
方法(例如 Contains, IndexOf) LastIndexOf对 Remove 列表元素使用相等比较器。 类型
T
的默认相等比较器按如下方式确定。 如果类型T
实现 IEquatable<T> 泛型接口,则相等比较器是 Equals(T) 该接口的方法;否则,默认相等比较器为 Object.Equals(Object)。用于列表元素的排序比较器等BinarySearchSort方法。 类型
T
的默认比较器按如下方式确定。 如果类型T
实现 IComparable<T> 泛型接口,则默认比较器是 CompareTo(T) 该接口的方法;否则,如果类型T
实现非泛型 IComparable 接口,则默认比较器是 CompareTo(Object) 该接口的方法。 如果类型T
未实现这两个接口,则没有默认比较器,并且必须显式提供比较器或比较委托。
List<T>不能保证排序。 必须先对需要List<T>排序的操作(例如BinarySearch)进行排序List<T>。
可以使用整数索引访问此集合中的元素。 此集合中的索引从零开始。
仅限 .NET Framework:对于非常大List<T>的对象,可以通过将配置元素的属性<gcAllowVeryLargeObjects>
设置为enabled
true
在运行时环境中,将 64 位系统上的最大容量增加到 20 亿个元素。
List<T> 接受 null
为引用类型的有效值,并允许重复元素。
有关类的 List<T> 不可变版本,请参阅 ImmutableList<T>。
性能注意事项
在决定是否使用 List<T> 或 ArrayList 类时,这两者都具有类似的功能,请记住 List<T> ,在大多数情况下,该类的性能更好,并且类型安全。 如果引用类型用于类的类型T
List<T>,则这两个类的行为是相同的。 但是,如果值类型用于类型 T
,则需要考虑实现和装箱问题。
如果某个值类型用于类型 T
,编译器将生成特定于该值类型的类的 List<T> 实现。 这意味着,在使用元素之前,不必装箱对象的列表元素 List<T> ,在创建大约 500 个列表元素后,通过不装箱列表元素保存的内存大于用于生成类实现的内存。
确保用于类型 T
的值类型实现 IEquatable<T> 泛型接口。 否则,诸如 Contains 方法必须调用 Object.Equals(Object) 该方法,该方法将受影响的列表元素装箱。 如果值类型实现 IComparable 接口,并且你拥有源代码,还实现 IComparable<T> 泛型接口以防止 BinarySearch 和 Sort 方法装箱列表元素。 如果你不拥有源代码,请将对象 IComparer<T> 传递给 BinarySearch 和 Sort 方法。
使用类的特定于类型的实现 List<T> ,而不是使用 ArrayList 类或自行编写强类型包装器集合是有好处的。 这是因为你的实现必须为你执行 .NET 的作用,而 .NET 运行时可以共享你的实现无法实现的公共中间语言代码和元数据。
F# 注意事项
该 List<T> 类在 F# 代码中不常使用。 相反, 通常首选列表(不可变、单选链接的列表)。 F# List
提供有序的不可变值系列,并且支持在功能样式开发中使用。 从 F# 使用时, List<T> 通常由 ResizeArray<'T>
类型缩写引用该类,以避免与 F# 列表的命名冲突。
示例
以下示例演示如何在 .. 中添加、删除和插入简单的业务对象 List<T>。
using System;
using System.Collections.Generic;
// Simple business object. A PartId is used to identify the type of part
// but the part name can change.
public class Part : IEquatable<Part>
{
public string PartName { get; set; }
public int PartId { get; set; }
public override string ToString()
{
return "ID: " + PartId + " Name: " + PartName;
}
public override bool Equals(object obj)
{
if (obj == null) return false;
Part objAsPart = obj as Part;
if (objAsPart == null) return false;
else return Equals(objAsPart);
}
public override int GetHashCode()
{
return PartId;
}
public bool Equals(Part other)
{
if (other == null) return false;
return (this.PartId.Equals(other.PartId));
}
// Should also override == and != operators.
}
public class Example
{
public static void Main()
{
// Create a list of parts.
List<Part> parts =
[
// Add parts to the list.
new Part() { PartName = "crank arm", PartId = 1234 },
new Part() { PartName = "chain ring", PartId = 1334 },
new Part() { PartName = "regular seat", PartId = 1434 },
new Part() { PartName = "banana seat", PartId = 1444 },
new Part() { PartName = "cassette", PartId = 1534 },
new Part() { PartName = "shift lever", PartId = 1634 },
];
// Write out the parts in the list. This will call the overridden ToString method
// in the Part class.
Console.WriteLine();
foreach (Part aPart in parts)
{
Console.WriteLine(aPart);
}
// Check the list for part #1734. This calls the IEquatable.Equals method
// of the Part class, which checks the PartId for equality.
Console.WriteLine("\nContains(\"1734\"): {0}",
parts.Contains(new Part { PartId = 1734, PartName = "" }));
// Insert a new item at position 2.
Console.WriteLine("\nInsert(2, \"1834\")");
parts.Insert(2, new Part() { PartName = "brake lever", PartId = 1834 });
//Console.WriteLine();
foreach (Part aPart in parts)
{
Console.WriteLine(aPart);
}
Console.WriteLine("\nParts[3]: {0}", parts[3]);
Console.WriteLine("\nRemove(\"1534\")");
// This will remove part 1534 even though the PartName is different,
// because the Equals method only checks PartId for equality.
parts.Remove(new Part() { PartId = 1534, PartName = "cogs" });
Console.WriteLine();
foreach (Part aPart in parts)
{
Console.WriteLine(aPart);
}
Console.WriteLine("\nRemoveAt(3)");
// This will remove the part at index 3.
parts.RemoveAt(3);
Console.WriteLine();
foreach (Part aPart in parts)
{
Console.WriteLine(aPart);
}
/*
ID: 1234 Name: crank arm
ID: 1334 Name: chain ring
ID: 1434 Name: regular seat
ID: 1444 Name: banana seat
ID: 1534 Name: cassette
ID: 1634 Name: shift lever
Contains("1734"): False
Insert(2, "1834")
ID: 1234 Name: crank arm
ID: 1334 Name: chain ring
ID: 1834 Name: brake lever
ID: 1434 Name: regular seat
ID: 1444 Name: banana seat
ID: 1534 Name: cassette
ID: 1634 Name: shift lever
Parts[3]: ID: 1434 Name: regular seat
Remove("1534")
ID: 1234 Name: crank arm
ID: 1334 Name: chain ring
ID: 1834 Name: brake lever
ID: 1434 Name: regular seat
ID: 1444 Name: banana seat
ID: 1634 Name: shift lever
RemoveAt(3)
ID: 1234 Name: crank arm
ID: 1334 Name: chain ring
ID: 1834 Name: brake lever
ID: 1444 Name: banana seat
ID: 1634 Name: shift lever
*/
}
}
' Simple business object. A PartId is used to identify the type of part
' but the part name can change.
Public Class Part
Implements IEquatable(Of Part)
Public Property PartName() As String
Get
Return m_PartName
End Get
Set(value As String)
m_PartName = value
End Set
End Property
Private m_PartName As String
Public Property PartId() As Integer
Get
Return m_PartId
End Get
Set(value As Integer)
m_PartId = value
End Set
End Property
Private m_PartId As Integer
Public Overrides Function ToString() As String
Return "ID: " & PartId & " Name: " & PartName
End Function
Public Overrides Function Equals(obj As Object) As Boolean
If obj Is Nothing Then
Return False
End If
Dim objAsPart As Part = TryCast(obj, Part)
If objAsPart Is Nothing Then
Return False
Else
Return Equals(objAsPart)
End If
End Function
Public Overrides Function GetHashCode() As Integer
Return PartId
End Function
Public Overloads Function Equals(other As Part) As Boolean _
Implements IEquatable(Of Part).Equals
If other Is Nothing Then
Return False
End If
Return (Me.PartId.Equals(other.PartId))
End Function
' Should also override == and != operators.
End Class
Public Class Example
Public Shared Sub Main()
' Create a list of parts.
Dim parts As New List(Of Part)()
' Add parts to the list.
parts.Add(New Part() With {
.PartName = "crank arm",
.PartId = 1234
})
parts.Add(New Part() With {
.PartName = "chain ring",
.PartId = 1334
})
parts.Add(New Part() With {
.PartName = "regular seat",
.PartId = 1434
})
parts.Add(New Part() With {
.PartName = "banana seat",
.PartId = 1444
})
parts.Add(New Part() With {
.PartName = "cassette",
.PartId = 1534
})
parts.Add(New Part() With {
.PartName = "shift lever",
.PartId = 1634
})
' Write out the parts in the list. This will call the overridden ToString method
' in the Part class.
Console.WriteLine()
For Each aPart As Part In parts
Console.WriteLine(aPart)
Next
' Check the list for part #1734. This calls the IEquatable.Equals method
' of the Part class, which checks the PartId for equality.
Console.WriteLine(vbLf & "Contains(""1734""): {0}", parts.Contains(New Part() With {
.PartId = 1734,
.PartName = ""
}))
' Insert a new item at position 2.
Console.WriteLine(vbLf & "Insert(2, ""1834"")")
parts.Insert(2, New Part() With {
.PartName = "brake lever",
.PartId = 1834
})
'Console.WriteLine();
For Each aPart As Part In parts
Console.WriteLine(aPart)
Next
Console.WriteLine(vbLf & "Parts[3]: {0}", parts(3))
Console.WriteLine(vbLf & "Remove(""1534"")")
' This will remove part 1534 even though the PartName is different,
' because the Equals method only checks PartId for equality.
parts.Remove(New Part() With {
.PartId = 1534,
.PartName = "cogs"
})
Console.WriteLine()
For Each aPart As Part In parts
Console.WriteLine(aPart)
Next
Console.WriteLine(vbLf & "RemoveAt(3)")
' This will remove part at index 3.
parts.RemoveAt(3)
Console.WriteLine()
For Each aPart As Part In parts
Console.WriteLine(aPart)
Next
End Sub
'
' This example code produces the following output:
' ID: 1234 Name: crank arm
' ID: 1334 Name: chain ring
' ID: 1434 Name: regular seat
' ID: 1444 Name: banana seat
' ID: 1534 Name: cassette
' ID: 1634 Name: shift lever
'
' Contains("1734"): False
'
' Insert(2, "1834")
' ID: 1234 Name: crank arm
' ID: 1334 Name: chain ring
' ID: 1834 Name: brake lever
' ID: 1434 Name: regular seat
' ID: 1444 Name: banana seat
' ID: 1534 Name: cassette
' ID: 1634 Name: shift lever
'
' Parts[3]: ID: 1434 Name: regular seat
'
' Remove("1534")
'
' ID: 1234 Name: crank arm
' ID: 1334 Name: chain ring
' ID: 1834 Name: brake lever
' ID: 1434 Name: regular seat
' ID: 1444 Name: banana seat
' ID: 1634 Name: shift lever
' '
' RemoveAt(3)
'
' ID: 1234 Name: crank arm
' ID: 1334 Name: chain ring
' ID: 1834 Name: brake lever
' ID: 1444 Name: banana seat
' ID: 1634 Name: shift lever
'
End Class
// Simple business object. A PartId is used to identify the type of part
// but the part name can change.
[<CustomEquality; NoComparison>]
type Part = { PartId : int ; mutable PartName : string } with
override this.GetHashCode() = hash this.PartId
override this.Equals(other) =
match other with
| :? Part as p -> this.PartId = p.PartId
| _ -> false
override this.ToString() = sprintf "ID: %i Name: %s" this.PartId this.PartName
[<EntryPoint>]
let main argv =
// We refer to System.Collections.Generic.List<'T> by its type
// abbreviation ResizeArray<'T> to avoid conflicts with the F# List module.
// Note: In F# code, F# linked lists are usually preferred over
// ResizeArray<'T> when an extendable collection is required.
let parts = ResizeArray<_>()
parts.Add({PartName = "crank arm" ; PartId = 1234})
parts.Add({PartName = "chain ring"; PartId = 1334 })
parts.Add({PartName = "regular seat"; PartId = 1434 })
parts.Add({PartName = "banana seat"; PartId = 1444 })
parts.Add({PartName = "cassette"; PartId = 1534 })
parts.Add({PartName = "shift lever"; PartId = 1634 })
// Write out the parts in the ResizeArray. This will call the overridden ToString method
// in the Part type
printfn ""
parts |> Seq.iter (fun p -> printfn "%O" p)
// Check the ResizeArray for part #1734. This calls the IEquatable.Equals method
// of the Part type, which checks the PartId for equality.
printfn "\nContains(\"1734\"): %b" (parts.Contains({PartId=1734; PartName=""}))
// Insert a new item at position 2.
printfn "\nInsert(2, \"1834\")"
parts.Insert(2, { PartName = "brake lever"; PartId = 1834 })
// Write out all parts
parts |> Seq.iter (fun p -> printfn "%O" p)
printfn "\nParts[3]: %O" parts.[3]
printfn "\nRemove(\"1534\")"
// This will remove part 1534 even though the PartName is different,
// because the Equals method only checks PartId for equality.
// Since Remove returns true or false, we need to ignore the result
parts.Remove({PartId=1534; PartName="cogs"}) |> ignore
// Write out all parts
printfn ""
parts |> Seq.iter (fun p -> printfn "%O" p)
printfn "\nRemoveAt(3)"
// This will remove the part at index 3.
parts.RemoveAt(3)
// Write out all parts
printfn ""
parts |> Seq.iter (fun p -> printfn "%O" p)
0 // return an integer exit code
以下示例演示了类型字符串的泛型类的 List<T> 多个属性和方法。 (有关复杂类型的示例 List<T> ,请参阅 Contains 方法。
无参数构造函数用于创建具有默认容量的字符串列表。 此时会显示该 Capacity 属性,然后使用 Add 该方法添加多个项。 列出项,并 Capacity 再次显示属性以及 Count 该属性,以显示容量已根据需要增加。
该方法 Contains 用于测试列表中是否存在项, Insert 该方法用于在列表中间插入新项,并再次显示列表的内容。
默认 Item[] 属性(C# 中的索引器)用于检索项, Remove 该方法用于删除前面添加的重复项的第一个实例,并再次显示内容。 该方法 Remove 始终删除它遇到的第一个实例。
该方法 TrimExcess 用于减少容量以匹配计数,并 Capacity 显示属性 Count 。 如果未使用的容量小于总容量的 10%,则不会调整列表的大小。
最后, Clear 该方法用于从列表中删除所有项,并 Capacity 显示属性 Count 。
List<string> dinosaurs = new List<string>();
Console.WriteLine("\nCapacity: {0}", dinosaurs.Capacity);
dinosaurs.Add("Tyrannosaurus");
dinosaurs.Add("Amargasaurus");
dinosaurs.Add("Mamenchisaurus");
dinosaurs.Add("Deinonychus");
dinosaurs.Add("Compsognathus");
Console.WriteLine();
foreach (string dinosaur in dinosaurs)
{
Console.WriteLine(dinosaur);
}
Console.WriteLine("\nCapacity: {0}", dinosaurs.Capacity);
Console.WriteLine("Count: {0}", dinosaurs.Count);
Console.WriteLine("\nContains(\"Deinonychus\"): {0}",
dinosaurs.Contains("Deinonychus"));
Console.WriteLine("\nInsert(2, \"Compsognathus\")");
dinosaurs.Insert(2, "Compsognathus");
Console.WriteLine();
foreach (string dinosaur in dinosaurs)
{
Console.WriteLine(dinosaur);
}
// Shows accessing the list using the Item property.
Console.WriteLine("\ndinosaurs[3]: {0}", dinosaurs[3]);
Console.WriteLine("\nRemove(\"Compsognathus\")");
dinosaurs.Remove("Compsognathus");
Console.WriteLine();
foreach (string dinosaur in dinosaurs)
{
Console.WriteLine(dinosaur);
}
dinosaurs.TrimExcess();
Console.WriteLine("\nTrimExcess()");
Console.WriteLine("Capacity: {0}", dinosaurs.Capacity);
Console.WriteLine("Count: {0}", dinosaurs.Count);
dinosaurs.Clear();
Console.WriteLine("\nClear()");
Console.WriteLine("Capacity: {0}", dinosaurs.Capacity);
Console.WriteLine("Count: {0}", dinosaurs.Count);
/* This code example produces the following output:
Capacity: 0
Tyrannosaurus
Amargasaurus
Mamenchisaurus
Deinonychus
Compsognathus
Capacity: 8
Count: 5
Contains("Deinonychus"): True
Insert(2, "Compsognathus")
Tyrannosaurus
Amargasaurus
Compsognathus
Mamenchisaurus
Deinonychus
Compsognathus
dinosaurs[3]: Mamenchisaurus
Remove("Compsognathus")
Tyrannosaurus
Amargasaurus
Mamenchisaurus
Deinonychus
Compsognathus
TrimExcess()
Capacity: 5
Count: 5
Clear()
Capacity: 5
Count: 0
*/
Public Class Example2
Public Shared Sub Main()
Dim dinosaurs As New List(Of String)
Console.WriteLine(vbLf & "Capacity: {0}", dinosaurs.Capacity)
dinosaurs.Add("Tyrannosaurus")
dinosaurs.Add("Amargasaurus")
dinosaurs.Add("Mamenchisaurus")
dinosaurs.Add("Deinonychus")
dinosaurs.Add("Compsognathus")
Console.WriteLine()
For Each dinosaur As String In dinosaurs
Console.WriteLine(dinosaur)
Next
Console.WriteLine(vbLf & "Capacity: {0}", dinosaurs.Capacity)
Console.WriteLine("Count: {0}", dinosaurs.Count)
Console.WriteLine(vbLf & "Contains(""Deinonychus""): {0}",
dinosaurs.Contains("Deinonychus"))
Console.WriteLine(vbLf & "Insert(2, ""Compsognathus"")")
dinosaurs.Insert(2, "Compsognathus")
Console.WriteLine()
For Each dinosaur As String In dinosaurs
Console.WriteLine(dinosaur)
Next
' Shows how to access the list using the Item property.
Console.WriteLine(vbLf & "dinosaurs(3): {0}", dinosaurs(3))
Console.WriteLine(vbLf & "Remove(""Compsognathus"")")
dinosaurs.Remove("Compsognathus")
Console.WriteLine()
For Each dinosaur As String In dinosaurs
Console.WriteLine(dinosaur)
Next
dinosaurs.TrimExcess()
Console.WriteLine(vbLf & "TrimExcess()")
Console.WriteLine("Capacity: {0}", dinosaurs.Capacity)
Console.WriteLine("Count: {0}", dinosaurs.Count)
dinosaurs.Clear()
Console.WriteLine(vbLf & "Clear()")
Console.WriteLine("Capacity: {0}", dinosaurs.Capacity)
Console.WriteLine("Count: {0}", dinosaurs.Count)
End Sub
End Class
' This code example produces the following output:
'
'Capacity: 0
'
'Tyrannosaurus
'Amargasaurus
'Mamenchisaurus
'Deinonychus
'Compsognathus
'
'Capacity: 8
'Count: 5
'
'Contains("Deinonychus"): True
'
'Insert(2, "Compsognathus")
'
'Tyrannosaurus
'Amargasaurus
'Compsognathus
'Mamenchisaurus
'Deinonychus
'Compsognathus
'
'dinosaurs(3): Mamenchisaurus
'
'Remove("Compsognathus")
'
'Tyrannosaurus
'Amargasaurus
'Mamenchisaurus
'Deinonychus
'Compsognathus
'
'TrimExcess()
'Capacity: 5
'Count: 5
'
'Clear()
'Capacity: 5
'Count: 0
[<EntryPoint>]
let main argv =
// We refer to System.Collections.Generic.List<'T> by its type
// abbreviation ResizeArray<'T> to avoid conflict with the List module.
// Note: In F# code, F# linked lists are usually preferred over
// ResizeArray<'T> when an extendable collection is required.
let dinosaurs = ResizeArray<_>()
// Write out the dinosaurs in the ResizeArray.
let printDinosaurs() =
printfn ""
dinosaurs |> Seq.iter (fun p -> printfn "%O" p)
printfn "\nCapacity: %i" dinosaurs.Capacity
dinosaurs.Add("Tyrannosaurus")
dinosaurs.Add("Amargasaurus")
dinosaurs.Add("Mamenchisaurus")
dinosaurs.Add("Deinonychus")
dinosaurs.Add("Compsognathus")
printDinosaurs()
printfn "\nCapacity: %i" dinosaurs.Capacity
printfn "Count: %i" dinosaurs.Count
printfn "\nContains(\"Deinonychus\"): %b" (dinosaurs.Contains("Deinonychus"))
printfn "\nInsert(2, \"Compsognathus\")"
dinosaurs.Insert(2, "Compsognathus")
printDinosaurs()
// Shows accessing the list using the Item property.
printfn "\ndinosaurs[3]: %s" dinosaurs.[3]
printfn "\nRemove(\"Compsognathus\")"
dinosaurs.Remove("Compsognathus") |> ignore
printDinosaurs()
dinosaurs.TrimExcess()
printfn "\nTrimExcess()"
printfn "Capacity: %i" dinosaurs.Capacity
printfn "Count: %i" dinosaurs.Count
dinosaurs.Clear()
printfn "\nClear()"
printfn "Capacity: %i" dinosaurs.Capacity
printfn "Count: %i" dinosaurs.Count
0 // return an integer exit code
(* This code example produces the following output:
Capacity: 0
Tyrannosaurus
Amargasaurus
Mamenchisaurus
Deinonychus
Compsognathus
Capacity: 8
Count: 5
Contains("Deinonychus"): true
Insert(2, "Compsognathus")
Tyrannosaurus
Amargasaurus
Compsognathus
Mamenchisaurus
Deinonychus
Compsognathus
dinosaurs[3]: Mamenchisaurus
Remove("Compsognathus")
Tyrannosaurus
Amargasaurus
Mamenchisaurus
Deinonychus
Compsognathus
TrimExcess()
Capacity: 5
Count: 5
Clear()
Capacity: 5
Count: 0
*)