SoFunction
Updated on 2025-03-01

Introduction to C# List and specific usage

1. # List generic collection

Collections are an important concept in OOP, and the comprehensive support for collections in C# is one of the essences of the language.

Why use generic collections?

Before C# 2.0, collections could be implemented mainly in two ways:

a.Use ArrayList

Putting objects directly into an ArrayList is intuitive, but since the items in the collection are of Object type, it is necessary to perform tedious type conversion every time you use it.

b. Use custom collection classes

A more common approach is to inherit a custom class from the CollectionBase abstract class and implement strongly typed collections by encapsulating IList objects. This method requires writing a corresponding custom class for each collection type, which is a lot of work. The emergence of generic collections solves the above problem better, and can create a set of specified types in just one line of code.

What is a generic?

Generics are new elements in C# 2.0 (called templates in C++) and are mainly used to solve a series of similar problems. This mechanism allows the class name to be passed as a parameter to a generic type and the corresponding object is generated. It may be better to think of generics (including classes, interfaces, methods, delegates, etc.) as templates. The variant part in the template will be replaced by the class name passed in as parameters, thus obtaining a new type definition. Generics are a relatively large topic, and no detailed analysis is made here. Interested people can consult relevant information.

How to create a generic collection?

The collection is mainly created using the List<T> generic class below the namespace, with the syntax as follows:

List<T> ListOfT = new List<T>();

The "T" in it is the type to be used, which can be either a simple type, such as string, int, or a user-defined type. Let’s see a specific example below.

The Person class is defined as follows:

class Person
{
  private string _name; //Name  private int _age; //age  //Create Person object  public Person(string Name, int Age)
  {
    this._name= Name;
    this._age = Age;
  }
  //Name  public string Name
  {
    get { return _name; }
  }
  //age  public int Age
  {
    get { return _age; }
  }
}

//Create Person objectPerson p1 = new Person("Zhang San", 30);
Person p2 = new Person("Li Si", 20);
Person p3 = new Person("Wang Wu", 50);
//Create a collection of objects of type PersonList&lt;Person&gt; persons = new List&lt;Person&gt;();
//Put Person object into collection(p1);
(p2);
(p3);
//Export the name of the second person(persons[1].Name);

It can be seen that generic collections greatly simplify the implementation code of the collection, through which it can easily create collections of specified types. Not only that, generic collections also provide more powerful functions. Let’s take a look at the sorting and searching in it.

Sort of generic collections

Sort is based on comparison. To sort, you must first compare. For example, if there are two numbers 1 and 2, to sort them, first you need to compare these two numbers and sort them according to the comparison results. If you want to compare objects, the situation will be more complicated. For example, comparing Person objects can be compared by name or by age, which requires determining the comparison rules. An object can have multiple comparison rules, but there can only be one default rule, and the default rule is placed in the class that defines the object. The default comparison rules are defined in the CompareTo method, which belongs to the IComparable<T> generic interface. Please see the following code:

class Person :IComparable&lt;Person&gt;
{
  //Compare by age  public int CompareTo(Person p)
  {
    return  - ;
  }
}

The parameter of the CompareTo method is another object of the same type to be compared with. The return value is of type int. If the return value is greater than 0, it means that the first object is greater than the second object. If the return value is less than 0, it means that the first object is less than the second object. If the return value is less than 0, the two objects are equal.

After defining the default comparison rules, you can sort the collection through the Sort method without parameters, as shown below:

//Sort the collection according to the default rules();
//Output everyone's nameforeach (Person p in persons)
{
  (); //The output order is "Li Si", "Zhang San", and "Wang Wu"}

In actual use, it is often necessary to sort the collections according to many different rules, which requires defining other comparison rules. They can be defined in the Compare method. This method belongs to the IComparer<T> generic interface. Please see the following code:

class NameComparer : IComparer&lt;Person&gt;
{
  //Storing the sorter instance  public static NameComparer Default = new NameComparer();
  //Compare by name  public int Compare(Person p1, Person p2)
  {
    return (, );
  }
}

The parameters of the Compare method are two objects of the same type to be compared. The return value is of type int, and the return value processing rules are the same as the CompareTo method. This returns a built-in Comparer object for comparing two objects of the same type.

The set is sorted using the newly defined comparator:

//Sort the collection by name(); 
//Output everyone's nameforeach (Person p in persons) 
{ 
(); //The output order is "Li Si", "Wang Wu", and "Zhang San"} 

You can also sort the collection through delegate. First, you need to define a method for delegate call to store comparison rules, and you can use static methods. Please see the following code:

class PersonComparison 
{ 
//Compare by namepublic static int Name(Person p1, Person p2) 
{ 
return (, ); 
} 
} 

The parameters of the method are two objects of the same type to be compared. The return value is of type int, and the return value processing rules are the same as the CompareTo method. Then sort the collections through the built-in generic delegate <T>:

&lt;Person&gt; NameComparison = new 
&lt;Person&gt;(); 
(NameComparison); 
//Output everyone's nameforeach (Person p in persons) 
{ 
(); //The output order is "Li Si", "Wang Wu", and "Zhang San"} 

As you can see, the latter two methods can sort the collections according to the specified rules, but the author prefers to use the delegate method. You can consider putting various comparison rules in one class and then making flexible calls.

Search for generic collections

Search is to find items that meet specific conditions from the set, define multiple search conditions, and call them as needed.

First, define the search criteria as follows:

class PersonPredicate
{
  //Find out middle-aged people (over 40 years old)  public static bool MidAge(Person p)
  {

    if ( &gt;= 40)
      return true;
    else
      return false;
  }
}

The search criteria above are placed in a static method. The return type of the method is Boolean. Items in the set that meet certain conditions return true, otherwise false will be returned. Then search the collection via the built-in generic delegate <T>:

&lt;Person&gt; MidAgePredicate = new &lt;Person&gt;();
List&lt;Person&gt; MidAgePersons = (MidAgePredicate);
//Export all middle-aged people's names
foreach (Person p in MidAgePersons)
{
  (); //Output "King Wu"}

Extensions of generic collections

What should I do if I want to get the names of everyone in the collection, separated by commas in the middle?

Considering that the functions a single class can provide are limited, it is natural to think of extending the List<T> class, and generic classes are also classes, so they can be extended through inheritance. Please see the following code:

//Define Persons collection classclass Persons : List&lt;Person&gt;
{
  //Get the names of everyone in the collection  public string GetAllNames()
  {
    if ( == 0)
      return "";
    string val = "";
    foreach (Person p in this)
    {
      val +=  + ",";
    }
    return (0,  - 1);
  }
}
//Create and populate Persons collectionPersons PersonCol = new Persons();
(p1);
(p2);
(p3);
//Output everyone's name(()); //Output "Zhang San, Li Si, Wang Wu"

2. List methods and properties Methods or properties Function

Capacity is used to get or set the number of elements that List can accommodate. This value will automatically increase when the quantity exceeds the capacity. You can set this value to reduce capacity, or you can call the trin() method to reduce capacity to fit the actual number of elements.

Count property, used to get the current number of elements in the array

Item( ) gets or sets elements by specifying an index. For List class, it is an indexer.

Add( ) Public method to add an object in List

AddRange( ) public method, add multiple elements that implement the ICollection interface at the end of List

BinarySearch() overloaded public method used to locate specified elements using binary search within a sorted List.

Clear( ) Removes all elements in List

Contains( ) Tests whether an element is in List

CopyTo( ) overloads a public method to copy a List into a one-dimensional array

Exists( ) Tests whether an element is in List

Find( ) Find and return the first matching element that appears in the List

FindAll( ) Find and return all matching elements in List

GetEnumerator( ) overloaded public method, returning an enumerator for iterating on List

Getrange( ) Copy elements in the specified range into a new List

IndexOf( ) overloads public method to find and return the index of each matching element

Insert( ) Insert an element in List

InsertRange( ) Insert a set of elements in List

LastIndexOf( ) overloaded public method, finds and returns the index of the last matching element

Remove( ) Removes the first element that matches the specified element

RemoveAt( ) Removes the element of the specified index

RemoveRange( ) Removes elements of the specified range

Reverse( ) Reverse( ) Reverse the order of elements in List

Sort( ) sorts elements in List

ToArray( ) Copy the elements in List into a new array

trimToSize( ) Set capacity to the actual number of elements in List

3. How to use List

1. Basics and common methods of List:

(1) Statement:

①、List<T> mList = new List<T>(); 
T is the element type in the list, now take the string type as an example

List<string> mList = new List<string>();

②、List<T> testList =new List<T> (IEnumerable<T> collection);

Create a List with a collection as a parameter:

string[] temArr = { "Ha", "Hunter", "Tom", "Lily", "Jay", "Jim", "Kuku", "Locu" };
List<string> testList = new List<string>(temArr);

(2) Add elements:

①, add an element

Syntax: List. Add(T item)

List<string> mList = new List<string>();
("John");

②. Add a group of elements

Syntax: List. AddRange(IEnumerable<T> collection)

List<string> mList = new List<string>();
string[] temArr = { "Ha","Hunter", "Tom", "Lily", "Jay", "Jim", "Kuku", "Locu" };
(temArr);

③, add an element in the index position

Syntax: Insert(int index, T item);

List<string> mList = new List<string>();
(1, "Hei");

④, traverse elements in List

grammar:

foreach (T element in mList) //T's type is the same as when mList declared{
  (element);
}

example:

List&lt;string&gt; mList = new List&lt;string&gt;();
...//Omit some codeforeach (string s in mList)
{
  (s);
}

(3) Delete elements:

①, delete a value

Syntax: List. Remove(T item)

("Hunter");

②. Delete the element with the index subscript

Syntax: List. RemoveAt(int index);

(0);

③. Starting from the index index, delete count elements

Syntax: List. RemoveRange(int index, int count);

(3, 2);

(4) Determine whether an element is in the List:

Syntax: List. Contains(T item)   The return value is true/false

if (("Hunter"))
{
  ("There is Hunter in the list");
}
else
{
  ("Hunter");
  ("Add Hunter successfully.");
}

(5) Sort the elements in List:

Syntax: List. Sort ()   The default is the first letter of the element in ascending order

();

(6) Reverse the order of elements in List:

Syntax: List. Reverse ()   Can be used in conjunction with List. Sort () to achieve the desired effect

mList. Reverse();

(7), List clear:

Syntax: List. Clear ()

();

(8) Obtain the number of elements in List:

Syntax: List. Count ()    Returns the int value

int count = ();
("The num of elements in the list: " +count);

2. Advanced and powerful methods of List:

List used in this paragraph:

string[] temArr = { "Ha","Hunter", "Tom", "Lily", "Jay", "Jim", "Kuku", " "Locu" };
(temArr);

(1) Method: Search all elements that match the conditions defined by the specified predicate.

Syntax: public List<T> FindAll(Predicate<T> match);

List&lt;string&gt; subList = (ListFind); //Delegate to ListFind functionforeach (string s in subList)
{
  ("element in subList: "+s);
}

At this time, subList stores all elements with length greater than 3.

(2) Method: Search for elements that match the conditions defined by the specified predicate and return the first matching element in the entire List.

Syntax: public T Find(Predicate<T> match);

Predicate is a delegate to a method, which returns true if the object passed to it matches the condition defined in the delegate. The elements of the current List are passed one by one to the Predicate delegate and move forward in the List, starting from the first element and ending with the last element. Processing stops when a match is found.

Predicate can be delegated to a function or a Ramda expression:

Delegate to Ramda expression:

string listFind = (name =&gt; //name is a variable, which represents the element in mList, set it yourself{   
  if ( &gt; 3)
  {
   return true;
  }
 return false;
});
(listFind);   //The output is Hunter

Delegate to a function:

string listFind1 = (ListFind); //Delegate to ListFind function(listFind);  //The output is Hunter
//ListFind functionpublic bool ListFind(string name)
{
  if ( &gt; 3)
  {
    return true;
  }
  return false;
}

The results of these two methods are the same.

(3) Method: Search for elements that match the conditions defined by the specified predicate and return the last matching element in the entire List.
Syntax: public T FindLast(Predicate<T> match);

The usage is the same as.

(4) Method: Determine whether each element in List matches the conditions defined by the specified predicate.

Syntax: public bool TrueForAll(Predicate<T> match);

Delegate to Ramda expression:

bool flag = (name =&gt;
{
  if ( &gt; 3)
  {
 return true;
  }
  else
  {
 return false;
  }
});
("True for all: "+flag); //flagThe value is

Delegate to a function, and use the ListFind function above:

bool flag = (ListFind);  //Delegate to ListFind function("True for all: "+flag); //flagThe value isfalse

The results of these two methods are the same.

(5)(n) Method: Obtain the first n lines. The return value is IEnumetable<T>, and the type of T is the same as the type of List<T>.

IEnumerable<string> takeList= (5);
foreach (string s in takeList)
{
   ("element in takeList: " + s);
}

At this time, the elements stored in takeList are the first 5 in mList.

(6) Method: Search all elements that match the conditions defined by the specified predicate. Similar to the method.

IEnumerable<string> whereList = (name =>
{
  if ( > 3)
  {
   return true;
  }
  else
 {
   return false;
 }
 });

foreach (string s in subList)
{
  ("element in subLis

At this time, subList stores all elements with length greater than 3.

(7) Method: Remove all elements that match the conditions defined by the specified predicate.

Syntax: public int RemoveAll(Predicate<T> match);

(name =>
{
   if ( > 3)
  {
    return true;
  }
  else
  {
    return false;
  }
});

foreach (string s in mList)
{
  ("element in mList:   " + s);
} 

At this time, mList stores elements whose length is greater than 3.

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.