A C# tutorial of List for beginners. The demo is carried out in ASP.NET WebForms.
Introduction
This article is about an introduction of using C# List<T>
and explained in ASP.NET WebForms environment.
Before Start
Creates a new project of ASP.NET WebForms, which commonly refers to the project type of ASP.NET Web Application (.NET Framework) in Visual Studio.
Here is a YouTube video guide for installing Visual Studio and creating new project of ASP.NET WebForm
s:
The ASP.NET page serves as an "output" to display the result of the coding.
After creating a new page. Here’s an example of initial ASP.NET front page code:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
</div>
</form>
</body>
</html>
Insert a component of PRE
block and PlaceHolder
into the page:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<pre><asp:PlaceHolder ID="ph1" runat="server"></asp:PlaceHolder></pre>
</form>
</body>
</html>
Go to code behind:
Here’s the initial code behind of a new page. The C# code demonstrated in the rest of this article will be placed within the main method of Page_Load
.
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
}
List<T> - a List of Objects
The letter “T
” in List<T>
refers to Object
Type.
It can be declared with any object
type. For example:
string object
int object
decimal object
DateTime object
- any
class object
- etc.
The Constructors of List<T>
Here are a few ways to create a List<T>
in C#.
The default constructor. This creates an empty list.
List<int> lstNo = new List<int>();
Using the List<T>(IEnumerable<T>) constructor. This will pre-populate with an array or an existing list.
<int> lstNo = new List<int> { 1, 2, 3, 4, 5 };
Using the List<T>(int) constructor. This creates a list of integers with a capacity of 10 elements, but no elements are added to the list.
List<int> lstNo = new List<int>(10);
Using the List<T>(int, T) constructor. This creates a list of integers with a capacity of 10 elements and 10 elements with a value of 0.
List<int> lstNo = new List<int>(10, 0);
List<T> is a reference type in C#
When a List<T> object is created and assigned to a variable, the variable becomes a reference to the object.
Example:
List<int> lstNo = new List<int> { 1, 2, 3, 4, 5 };
List<int> lstA = lstNo;
List<int> lstB = lstA;
These 3 variables of lstNo
, lstA
and lstB
hold the reference to the same List<int>
. If any of the content of the List
is modified, the changes will be applied the same to other List
. Put it simple, they are the same thing, they holds the same values.
The values stored in the List<T>
is however have two groups of TYPE
s:
Value Type and Reference Type
But anyway, this will be another article for another day. For now, you may refer to [this article] and [this article].
Adding and Getting Values from List<T>
Start with the string
object type.
List<string> lst = new List<string>();
Adding string
objects into the list.
List<string> lst = new List<string>();
lst.Add("book");
lst.Add("hello");
lst.Add("car");
lst.Add("part");
lst.Add("enter");
lst.Add("forest");
lst.Add("green");
Use the property of List<T>.Count
to get total objects in the List
:
lst.Count
Perform a loop to display the content within the List
.
Using Foreach Loop to Get Values
You can specify the exact object TYPE
in the foreach
declaration, for example:
foreach (string text in lst)
{ }
Or you can also use the keyword “var
” as a generic declaration of implicitly typed local variable, for example:
foreach (var text in lst)
{ }
They both works the same.
Let’s continue, performing foreach
loop.
List<string> lst = new List<string>();
lst.Add("book");
lst.Add("hello");
lst.Add("car");
lst.Add("part");
lst.Add("enter");
lst.Add("forest");
lst.Add("green");
StringBuilder sb = new StringBuilder();
sb.AppendLine($"Total objects in List: {lst.Count}");
sb.AppendLine("====================================");
foreach (var text in lst)
{
sb.AppendLine(text);
}
ph1.Controls.Add(new LiteralControl(sb.ToString()));
Press [F5] or run the website, here’s the output:
Total objects in List: 7
====================================
book
hello
car
part
enter
forest
green
Note:
The string
can also be combined by using string
operation of “+=”. For example:
string output = "";
foreach (var text in lst)
{
output += text + "<br />";
}
Note:
This will also produce the same output, but however, if you are running this in large amount of loops, using the string operation of “+=” will cause a lots of memory usage. String
object is immutable. An immutable object is an object that cannot be changed after it has been created. Every time a text is trying to append to it, a new string
object is created in memory. This will create a lots of strings in memory. StringBuilder
object does not has this problem. It is a specialized string handling object that can be altered and expanded on the go.
Using For Loop to Get Values
for (int i = 0; i < lst.Count; i++)
{
sb.AppendLine(lst[i]);
}
There are three sections in the declaration of a For
loop.
Section 1: Declare/set the initial value:
int i = 0;
Section 2: Set the looping condition:
i < lst.Count;
Section 3: Set the increment of value or changes of value foreach
loop:
i++
Loop from the first data in the List<T>
:
List<string> lst = new List<string>();
lst.Add("book");
lst.Add("hello");
lst.Add("car");
lst.Add("part");
lst.Add("enter");
lst.Add("forest");
lst.Add("green");
StringBuilder sb = new StringBuilder();
sb.AppendLine($"Total objects in List: {lst.Count}");
sb.AppendLine("====================================");
for (int i = 0; i < lst.Count; i++)
{
sb.AppendLine($"Loop {i}: {lst[i]}");
}
ph1.Controls.Add(new LiteralControl(sb.ToString()));
Press [F5] or run the website, and this will produce the following output:
Total objects in List: 7
====================================
Loop 0: book
Loop 1: hello
Loop 2: car
Loop 3: part
Loop 4: enter
Loop 5: forest
Loop 6: green
Loop from the last data in the List<T>
:
for (int i = lst.Count - 1; i >= 0; i--)
{
sb.AppendLine(lst[i]);
}
Output:
Total objects in List: 7
====================================
Loop 6: green
Loop 5: forest
Loop 4: enter
Loop 3: part
Loop 2: car
Loop 1: hello
Loop 0: book
To Get a Specific Value in List
Get the first value:
string output = lst[0];
ph1.Controls.Add(new LiteralControl(output);
Get the third value:
string output = lst[2];
ph1.Controls.Add(new LiteralControl(output);
Let’s do a simple HTML form to play around. Go to the ASP.NET front page, insert the following HTML & controls:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
Enter a number:
<asp:TextBox ID="txtNumber"
runat="server" Width="80px"></asp:TextBox>
<br />
<br />
<asp:Button ID="btGetValue" runat="server"
Text="Get Value" OnClick="btGetValue_Click" />
<br />
<br />
Output:
<hr />
<pre><asp:PlaceHolder ID="ph1"
runat="server"></asp:PlaceHolder></pre>
</form>
</body>
</html>
Go to code behind, the initial code behind will look something like this:
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btGetValue_Click(object sender, EventArgs e)
{
}
}
In the method of btGetValue_Click
, add a "try
" and "catch
" block code:
protected void btGetValue_Click(object sender, EventArgs e)
{
try
{
}
catch (Exception ex)
{
}
}
Before we continue, let's explains what is the usage of "try
" and "catch
" block code.
The block of "try
" and "catch
" are used to capture errors that might occur during real-time operation.
If there is any error occurs in the “try
” block, the operation will stop and falls down to the “catch
” block. An Exception
will be produced (An exception
is raised).
The Exception
contains the information/description of what kind of error that has been generated. It gives you a clue of how the error is generated.
Let’s try to make an error to see the effect.
First, declare a string
object in the “try
” block:
try
{
string aa = "hello";
}
catch (Exception ex)
{
string err_message = ex.Message;
ph1.Controls.Add(new LiteralControl(err_message));
}
Then, converts the string
into number:
try
{
string aa = "hello";
int num = Convert.ToInt32(a);
}
catch (Exception ex)
{
string err_message = ex.Message;
ph1.Controls.Add(new LiteralControl(err_message));
}
Display the output to front end:
try
{
string aa = "hello";
int num = Convert.ToInt32(a);
string output = num.ToString();
ph1.Controls.Add(new LiteralControl(output));
}
catch (Exception ex)
{
string err_message = ex.Message;
ph1.Controls.Add(new LiteralControl(err_message));
}
string aa
is a text and it’s not a numeric characters. Therefore, it can’t be converted into number and this will cause an error. Press [F5] to run the code and the following output will produce:
Input string was not in a correct format.
Let’s change the string aa
to numeric characters:
try
{
string aa = "123";
int num = Convert.ToInt32(a);
string output = num.ToString();
ph1.Controls.Add(new LiteralControl(output));
}
catch (Exception ex)
{
string err_message = ex.Message;
ph1.Controls.Add(new LiteralControl(err_message));
}
and this will be the output:
123
Let’s continue. Declare the list of string
s:
List<string> lst = new List<string>();
lst.Add("book");
lst.Add("hello");
lst.Add("car");
lst.Add("part");
lst.Add("enter");
lst.Add("forest");
lst.Add("green");
try
{
}
catch (Exception ex)
{
string err_message = ex.Message;
ph1.Controls.Add(new LiteralControl(err_message));
}
Now, we’ll going to capture the input value from the form submission. The form is considered “submitted” when the user click on the button “btGetValue
” which displayed as “Get Value” at user’s web browser.
try
{
string input = Request.Form["txtNumber"] + "";
}
catch (Exception ex)
{
string err_message = ex.Message;
ph1.Controls.Add(new LiteralControl(err_message));
}
Convert the input text into number:
try
{
string input = Request.Form["txtNumber"] + "";
int num = Convert.ToInt32(input);
}
catch (Exception ex)
{
string err_message = ex.Message;
ph1.Controls.Add(new LiteralControl(err_message));
}
As you can see, the value supplies by user is stored in the form input of "txtNumber
" (the textbox
). If the user enters non-numeric characters, this will cause the program to encouter error (raise Exception) and crash.
That's why a "try
" & "catch
" block is used to prevent the program from crashing and let the program keeps running.
Get the value from the string
and displays it to front end:
try
{
string input = Request.Form["txtNumber"] + "";
int num = Convert.ToInt32(input);
string output = lst[num];
ph1.Controls.Add(new LiteralControl(output));
}
catch (Exception ex)
{
string err_message = ex.Message;
ph1.Controls.Add(new LiteralControl(err_message));
}
Press [F5] and run the website.
Getting the fifth value:
Getting the seventh value:
Getting the 100th value: (error - there is no 100th value)
Entering non-numberic characters: (error - unable to convert into number)
Process User Input Data Without Using “try” and “catch”
Instead of using “try
” & “catch
“, use int.TryParse()
to test and convert the user input value.
string input = Request.Form["txtNumber"] + "";
int number = 0;
string output = "";
if (int.TryParse(input, out number))
{
if (number >= lst.Count)
{
output = "Index is out of range";
}
else
{
output = lst[number];
}
}
else
{
output = "Invalid input. Please enter numeric value.";
}
ph1.Controls.Add(new LiteralControl(output));
Changing the Values in List<T>
To change the values, just reassign new values to the list entries:
StringBuilder sb = new StringBuilder();
List<string> lst = new List<string>();
lst.Add("book");
lst.Add("hello");
lst.Add("car");
lst.Add("part");
lst.Add("enter");
lst.Add("forest");
lst.Add("green");
sb.AppendLine("===============");
sb.AppendLine("Before");
sb.AppendLine("===============");
int count = 0;
foreach (var text in lst)
{
count++;
sb.AppendLine($"Item {count}: {text}");
}
lst[0] = "apple";
lst[1] = "orange";
lst[2] = "grape";
lst[3] = "watermelon";
lst[4] = "lemon";
lst[5] = "banana";
lst[6] = "strawberry";
sb.AppendLine();
sb.AppendLine("===============");
sb.AppendLine("After");
sb.AppendLine("===============");
count = 0;
foreach (var text in lst)
{
count++;
sb.AppendLine($"Item {count}: {text}");
}
ph1.Controls.Add(new LiteralControl(sb.ToString()));
Output:
===============
Before
===============
Item 1: book
Item 2: hello
Item 3: car
Item 4: part
Item 5: enter
Item 6: forest
Item 7: green
===============
After
===============
Item 1: apple
Item 2: orange
Item 3: grape
Item 4: watermelon
Item 5: lemon
Item 6: banana
Item 7: strawberry
Insert Item into List<T>
The Insert
syntax has two parameters:
List.Insert(position, value);
The first parameter will be the position
of new item that will be inserted.
The second parameter is the value
.
For example, insert to the first position in the List
:
lst.Insert(0, "house");
Insert to the third position in the list:
lst.Insert(2, "house");
Remove Items from List<T>
Remove the first item:
lst.Remove(0);
Remove the fourth item:
lst.Remove(3);
Remove item with exact values:
lst.Remove("car");
To Check The Existence of Value
if (lst.Contains("book"))
{
sb.AppendLine("Yes, book exists");
}
else
{
sb.AppendLine("No, book is not existed")l
}
Example of List of int/decimal Object
Lets try the List
of int
object:
List<int> lst = new List<int>();
lst.Add(23);
lst.Add(234);
lst.Add(85);
lst.Add(933);
lst.Add(123);
lst.Add(345);
int total = 0;
foreach(var num in lst)
{
total += num;
}
string output = total.ToString();
ph1.Controls.Add(new LiteralControl(output));
Output:
1743
Example 2: List of decimal
object
List<decimal> lst = new List<decimal>();
lst.Add(34.234m);
lst.Add(234.88m);
lst.Add(8.15m);
lst.Add(933.66m);
lst.Add(123.1m);
lst.Add(345.09m);
decimal total = 10000m;
foreach (var num in lst)
{
total -= num;
}
string output = total.ToString();
ph1.Controls.Add(new LiteralControl(output));
Output:
8320.886
Declaring the List of Class Object
Let’s assume that the following class object is created:
class Member
{
public string Name { get; set; }
public string Tel { get; set; }
public string Location { get; set; }
}
Declaring List of Member
Object and display the name by using Foreach
Loop:
Member m1 = new Member();
m1.Name = "Sam";
m1.Tel = "2938273645";
m1.Location = "New York";
Member m2 = new Member()
{
Name = "Rose",
Tel = "9874563789",
Location = "Los Angelos"
};
Member m3 = new Member();
m3.Name = "Smith";
m3.Tel = "2348734985";
m3.Location = "Jacksonville";
List<Member> lst = new List<Member>();
lst.Add(m1);
lst.Add(m2);
lst.Add(m3);
StringBuilder sb = new StringBuilder();
int count = 0;
foreach (var m in lst)
{
count++;
sb.AppendLine($"No. {count}: {m.Name}, Location: {m.Location}");
}
ph1.Controls.Add(new LiteralControl(sb.ToString()));
Output:
No. 1: Sam, Location: New York
No. 2: Rose, Location: Los Angelos
No. 3: Smith, Location: Jacksonville
Let’s build a “Get Members” form that display the HTML table of Member
s’ Details. Build the ASP.NET front page as follows:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<style type="text/css">
table {
border-collapse: collapse;
}
th {
padding: 10px;
color: white;
background: #646464;
border-right: 1px solid #a7a7a7;
}
td {
border: 1px solid #a8a8a8;
padding: 10px;
}
tr:nth-child(odd){
background: #e6e6e6;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<asp:Button ID="btGetMembers" runat="server" Text="Get Members"
OnClick="btGetMembers_Click" />
<hr />
<asp:PlaceHolder ID="ph1" runat="server"></asp:PlaceHolder>
</form>
</body>
</html>
At the code behind:
protected void btGetMembers_Click(object sender, EventArgs e)
{
Member m1 = new Member();
m1.Name = "Sam";
m1.Tel = "2938273645";
m1.Location = "New York";
Member m2 = new Member()
{
Name = "Rose",
Tel = "9874563789",
Location = "Los Angelos"
};
Member m3 = new Member();
m3.Name = "Smith";
m3.Tel = "2348734985";
m3.Location = "Jacksonville";
List<Member> lst = new List<Member>();
lst.Add(m1);
lst.Add(m2);
lst.Add(m3);
StringBuilder sb = new StringBuilder();
sb.Append($@"
Total Members: {lst.Count}
<br /><br />
<table>
<tr>
<th>No</th>
<th>Member's Name</th>
<th>Tel</th>
<th>Location</th>
</tr>
");
int count = 0;
foreach (var m in lst)
{
count++;
sb.Append($@"
<tr>
<td>{count}</td>
<td>{m.Name}</td>
<td>{m.Tel}</td>
<td>{m.Location}</td>
</tr>
");
}
sb.Append("</table>");
ph1.Controls.Add(new LiteralControl(sb.ToString()));
}
The output:
Copying List<T>
Here are some of the common methods to copy a List<T>:
List<T>.AddRange
List<T>.Concat
List<T>.ToArray + List<T>.Add
List<T>.GetRange
List<T>.AddRange
Add all elements from another collection (i.e. List or Array) into it's own.
int[] arrayA = { 1, 2, 3, 4, 5};
List<int> lstB = new List<int> { 6, 7, 8, 9, };
List<int> lstC = new List<int>();
lstC.AddRange(arrayA);
lstC.AddRange(lstB);
List<T>.Concat
Combine with another list of elements.
int[] arrayA = { 1, 2, 3, 4, 5 };
List<int> lstB = new List<int> { 6, 7, 8, 9, };
List<int> lstC = lstB.Concat(arrayA).ToList();
There seems to have similarities between AddRange
and Concat
. The main difference between Concat
and AddRange
is that Concat
creates a new sequence that contains the elements of both sequences, while AddRange
modifies the original sequence and adds the elements of the other sequence to it.
List<T>.ToArray + List<T>.Add
Convert a list into an array and then add it into another list.
List<int> lstA = new List<int> { 6, 7, 8, 9, };
int[] arrayA = lstA.ToArray();
List<int> lstB = new List<int>();
foreach(int i in arrayA)
{
lstB.Add(i);
}
List<T>.GetRange
Get a range of elements and forms a new list.
List<int> lstA = new List<int> { 6, 7, 8, 9, };
List<int> lstX = lstA.GetRange(1, 4);
In above example, lstX
is a new list that has the values from lstA
with the elements starting at index 1 to index 4. Translate into English, it means, get all elements start at 2nd position to 5th position in the list.
Sorting List<T> (Rearrange the List in Specific Orders)
This article will introduce two methods:
- Method 1: By using “
List<T>.Sort()
“ - Method 2: By using “LINQ“
Method 1: By using “List<T>.Sort()”
Sorting a non-class object type list:
lst.Sort()
lst.Reverse();
lst.Sort((x, y) => x.CompareTo(y));
lst.Sort((x, y) => y.CompareTo(x));
Class object sort by one field, i.e., Name
(ascending order):
lst.Sort((x, y) => x.Name.CompareTo(y.Name));
lst.Sort(delegate (Member x, Member y) {
return x.Name.CompareTo(y.Name);
});
Sort by one element, i.e., Name
(descending order):
lst.Sort((x, y) => y.Name.CompareTo(n.Name));
lst.Sort(delegate (Member x, Member y) {
return y.Name.CompareTo(x.Name);
});
Sort by two elements, i.e., Name
and Location
(both ascending order):
lst.Sort(delegate (Member x, Member y) {
int a = x.Name.CompareTo(y.Name);
if (a == 0)
a = x.Location.CompareTo(y.Location);
return a;
});
Method 2: By using “LINQ”
Available common LINQ sorting commands:
OrderBy()
OrderByDescending()
ThenBy()
ThenByDescending()
Sort by one element, i.e., Name
(ascending order):
lst.OrderBy(a => a.Name);
Sort by one element, i.e., Name
(descending order):
lst.OrderByDescending(a => a.Name);
Sort by two elements, i.e., Name
and Location
(both ascending order):
lst.OrderBy(a => a.Name).ThenBy(a => a.Location);
History
- 16th December, 2022: Initial version