An Array as a Reference
An Array as a Reference
As is the case for variables of primitive types, you can pass an array by reference. To do that, in the parentheses of the function, before the ref keyword. This can be done as follows:
void Initialize(ref int[] coords)
{
}
When you call such a function, precede the argument with the ref keyword. This can be done as follows:
int[] points = new int[4];
Initialize(ref points);
void Initialize(ref int[] coords)
{
}
As is the case for values of primitive types, if you pass an array by reference, the function can modify the array. If that happens, when the function exits, the changes made on the array are kept. Here is an example:
int[] points = new int[4];
Initialize(ref points);
CreateCoordinate(points);
Console.WriteLine("======================================");
void Initialize(ref int[] coords)
{
coords = new int[] { 6, 3, -5, 0 };
}
void CreateCoordinate(int[] pts)
{
Console.WriteLine("Points Coordinates: P(" + pts[0] + ", " + pts[1] + "), Q(" + pts[2] + ", " + pts[1] + ")");
}
This would produce:
Points Coordinates: P(6, 3), Q(-5, 3) ====================================== Press any key to close this window . . .
Instead of just one, you can create a function that receives more than one array and you can create a function that receives a combination of one or more arrays and one or more regular arguments. You can also create a function that uses one or more arrays as parameter(s) and returns a regular value of a primitive type.
Passing an Array Out
As seen for passing an argument by reference, you can pass an array out. We saw that, when passing an array using the ref keyword, the function that receives the array doesn't have to initialize it. If the array was already initialized by the function that is making the call, the called function can simply change the values of the elements of the array. On the other hand, if you pass an array using the out keyword, the function that receives the out array must initialize it before exiting. Here is an example:
int[] points = new int[4];
Initialize(out points);
CreateCoordinate(points);
Console.WriteLine("======================================");
void Initialize(out int[] coords)
{
coords = new int[] { 1, 4, 2, -4 };
}
void CreateCoordinate(int[] pts)
{
Console.WriteLine("Points Coordinates: P(" + pts[0] + ", " + pts[1] + "), Q(" + pts[2] + ", " + pts[1] + ")");
}
Passing a Varied Number of Parameters
When you pass an array as argument or pass a combination of arrays and non-array arguments, when you call the function, you must pass the exact number of arguments. That is, you must know the number of arguments the function will process. An alternative to this is to pass only one array as argument. Then, when, or every time, you call the function, you can pass any number of values you want. That is, at one time you can call the function and pass 2 values. At another time, you can call the same function but pass more arguments to it.
To create a function that receives a varied number of arguments, in the parentheses of the method, type the params keyword followed by an array. Here is an example:
void ShowPoints(params int[] points) { }
As mentioned already, when calling the function, you can pass the number of arguments you want. It's important to know that the function that receives a params argument doesn't know the number of arguments it will receive when it is called. This means that you must find a way to access the arguments and you must find a way for the function to know the number of arguments it received. Because this information is not known to the function, the Array class provides a property named Length that holds the size of the array. Here are examples:
void Describe(params int[] pts)
{
int dimension = pts.Length;
if (dimension == 1)
{
Console.WriteLine("The point is located on a line.");
}
else if (dimension == 2)
{
Console.WriteLine("The point is located on a Cartesian coordinate system.");
}
else if (dimension == 3)
{
Console.WriteLine("The point is located on a 3-D coordinate system.");
}
else
{
Console.WriteLine("The point is located on a multi-dimensional system.");
}
}
Here are examples of calling a function that receives a params argument:
Console.WriteLine("Points Coordinates");
Console.WriteLine("======================================================");
// The method is called with one argument
Console.WriteLine("Coordinate: -6");
Describe(-6);
Console.WriteLine("------------------------------------------------------");
// The method is called with 4 arguments
Describe(2, 2, 5, -3);
Console.WriteLine("Coordinates: 2, 2, 5, -3");
Console.WriteLine("------------------------------------------------------");
// The method is called with two arguments
Console.WriteLine("Coordinates: 2, 5");
Describe(2, 5);
Console.WriteLine("------------------------------------------------------");
// The method is called with three arguments
Console.WriteLine("Coordinates: -4, 3, 1");
Describe(-4, 3, 1);
Console.WriteLine("======================================================");
void Describe(params int[] pts)
{
int dimension = pts.Length;
if (dimension == 1)
{
Console.WriteLine("The point is located on a line.");
}
else if (dimension == 2)
{
Console.WriteLine("The point is located on a Cartesian coordinate system.");
}
else if (dimension == 3)
{
Console.WriteLine("The point is located on a 3-D coordinate system.");
}
else
{
Console.WriteLine("The point is located on a multi-dimensional system.");
}
}
This would produce:
Points Coordinates ====================================================== Coordinate: -6 The point is located on a line. ------------------------------------------------------ The point is located on a multi-dimensional system. Coordinates: 2, 2, 5, -3 ------------------------------------------------------ Coordinates: 2, 5 The point is located on a Cartesian coordinate system. ------------------------------------------------------ Coordinates: -4, 3, 1 The point is located on a 3-D coordinate system. ====================================================== Press any key to close this window . . .
A Read-Only Array
Usually when you declare an array variable in a class (an array as opposed to other types of collections), you may already know the values you want the array to hold, and most of the time, you as the programmer will provide those values as opposed to the user providing them. To assist the compiler, you can create such an array as a read-only object. To do this, apply the readonly keyword to the variable. This can be done as follows:
using static System.Console;
StaffPayroll sp = new();
public class StaffPayroll
{
// Declaring an array without initializing it
readonly string[] fullName;
// Declaring and initializing an array
readonly double[] week1TimeWorked = new double[5];
// An array variable of numbers
readonly double[] week2TimeWorked = new double[5] { 6.00, 8.50, 7.00, 5.50, 6.50 };
public StaffPayroll()
{
// Initializing the array variable
fullName = new string[3];
fullName[0] = "Bethanie";
fullName[1] = "Elizabeth";
fullName[2] = "Gants";
WriteLine("Payroll Summary");
WriteLine("-----------------------------------------------");
WriteLine("Employee Name: {0} {1} {2}",
fullName[0], fullName[1], fullName[2]);
Prepare();
Present();
}
private void Prepare()
{
// Setting the values of the array that was declared and initialized
week1TimeWorked[0] = 8.00;
week1TimeWorked[1] = 6.00;
week1TimeWorked[2] = 9.00;
week1TimeWorked[3] = 8.50;
week1TimeWorked[4] = 7.50;
}
public void Present()
{
WriteLine("===============================================");
WriteLine("Time Worked");
WriteLine("-----------------------------------------------");
WriteLine("Week 1");
WriteLine(" Monday: {0:N}", week1TimeWorked[0]);
WriteLine(" Tuesday: {0:N}", week1TimeWorked[1]);
WriteLine(" Wednesday: {0:N}", week1TimeWorked[2]);
WriteLine(" Thursday: {0:N}", week1TimeWorked[3]);
WriteLine(" Friday: {0:N}", week1TimeWorked[4]);
WriteLine("-----------------------------------------------");
WriteLine("Week 2");
WriteLine(" Monday: {0:N}", week2TimeWorked[0]);
WriteLine(" Tuesday: {0:N}", week2TimeWorked[1]);
WriteLine(" Wednesday: {0:N}", week2TimeWorked[2]);
WriteLine(" Thursday: {0:N}", week2TimeWorked[3]);
WriteLine(" Friday: {0:N}", week2TimeWorked[4]);
WriteLine("-----------------------------------------------");
WriteLine("Total Time Worked: {0:N}",
week1TimeWorked[0] + week1TimeWorked[1] + week1TimeWorked[2] +
week1TimeWorked[3] + week1TimeWorked[4] + week2TimeWorked[0] +
week2TimeWorked[1] + week2TimeWorked[2] + week2TimeWorked[3] +
week2TimeWorked[4]);
WriteLine("===============================================");
}
}
This would produce:
Payroll Summary
-----------------------------------------------
Employee Name: Bethanie Elizabeth Gants
===============================================
Time Worked
-----------------------------------------------
Week 1
Monday: 8.00
Tuesday: 6.00
Wednesday: 9.00
Thursday: 8.50
Friday: 7.50
-----------------------------------------------
Week 2
Monday: 6.00
Tuesday: 8.50
Wednesday: 7.00
Thursday: 5.50
Friday: 6.50
-----------------------------------------------
Total Time Worked: 72.50
===============================================
Press any key to close this window . . .
A Read-Only Referenced Argument
Most of the time, the reason you want to pass an argument by reference is because you want its function to change the value of that argument. In some cases, you may not want the function to change the value of the argument, as is the case for an in argument. If you don't want a function to be able to change the value of a referenced argument, or to inform the compiler that you don't want the function to change the value of a referenced argument, you can pass the argument as read-only. To do this, when creating the function, between the ref keyword and the data type of the parameter, add the readonly keyword. When calling the function, you must pass the argument as a reference, by preceding the argument with the ref keyword. This can be done as follows:
using static System.Console; void Present(ref readonly double val) { WriteLine("Value: {0}", val); } double @double = 397_822.73; Present(ref @double); WriteLine("===================================");
This would produce:
Value: 397822.73 =================================== Press any key to close this window . . .
Remember that, if you pass an argument as ref readonly, you are not allowed to change the value of the argument in the body of the function. If you do, the compiler will produce an error.
Practical Learning: Passing Arguments as Read-Only References
using static System.Console;
PreparePayroll();
// -------------------------------------------------------
void IdentifyEmployee(out string fn, out string ln, out double sal)
{
WriteLine("FUN DEPARTMENT STORE");
WriteLine("=======================================================");
WriteLine("Payroll Preparation");
WriteLine("-------------------------------------------------------");
WriteLine("Enter the following pieces of information");
WriteLine("-------------------------------------------------------");
WriteLine("Employee Information");
WriteLine("-------------------------------------------------------");
Write("First Name: ");
fn = ReadLine()!;
Write("Last Name: ");
ln = ReadLine()!;
Write("Hourly Salary: ");
sal = double.Parse(ReadLine()!);
}
void GetTimeWorked(ref double m, ref double t, ref double w, ref double h, ref double f)
{
WriteLine("-------------------------------------------------------");
WriteLine("Time worked");
WriteLine("-------------------------------------------------------");
Write("Monday: ");
m = double.Parse(ReadLine()!);
Write("Tuesday: ");
t = double.Parse(ReadLine()!);
Write("Wednesday: ");
w = double.Parse(ReadLine()!);
Write("Thursday: ");
h = double.Parse(ReadLine()!);
Write("Friday: ");
f = double.Parse(ReadLine()!);
}
double Add2(ref readonly double m, ref readonly double n)
{
return m + n;
}
double Add5(in double a, in double b, in double c, in double d, in double e)
{
return a + b + c + d + e;
}
void EvaluateSalary(ref readonly double time, ref readonly double sal,
ref double regTime, ref double regPay, ref double overtime, ref double overPay)
{
regTime = time;
regPay = sal * time;
overtime = 0.00;
overPay = 0.00;
if (time is > 40.00)
{
regTime = 40.00;
regPay = sal * 40.00;
overtime = time - 40.00;
overPay = sal * 1.50 * overtime;
}
}
void PreparePayroll()
{
string firstName;
string lastName;
double hSalary;
double mon = 0.00;
double tue = 0.00;
double wed = 0.00;
double thu = 0.00;
double fri = 0.00;
double regularTime = 0.00;
double regularPay = 0.00;
double overtime = 0.00;
double overtimePay = 0.00;
IdentifyEmployee(out firstName, out lastName, out hSalary);
GetTimeWorked(ref mon, ref tue, ref wed, ref thu, ref fri);
double timeWorked = Add5(in mon, in tue, in wed, in thu, in fri);
EvaluateSalary(ref timeWorked, ref hSalary,
ref regularTime, ref regularPay, ref overtime, ref overtimePay);
double weeklyPay = Add2(ref regularPay, ref overtimePay);
WriteLine("+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+");
WriteLine("FUN DEPARTMENT STORE");
WriteLine("=======================================================");
WriteLine("Payroll Evaluation");
WriteLine("=======================================================");
WriteLine("Employee Information");
WriteLine("-------------------------------------------------------");
WriteLine($"Full Name: {firstName} {lastName}");
WriteLine($"Hourly Salary: {hSalary:f}");
WriteLine("=======================================================");
WriteLine("Time Worked Summary");
WriteLine("--------+---------+-----------+----------+-------------");
WriteLine(" Monday | Tuesday | Wednesday | Thursday | Friday");
WriteLine("--------+---------+-----------+----------+-------------");
WriteLine($" {mon:f} | {tue:f} | {wed:f} | {thu:f} | {fri:f}");
WriteLine("========+=========+===========+==========+=============");
WriteLine(" Pay Summary");
WriteLine("-------------------------------------------------------");
WriteLine(" Time Pay");
WriteLine("-------------------------------------------------------");
WriteLine($" Regular: {regularTime:f} {regularPay:f}");
WriteLine("-------------------------------------------------------");
WriteLine($" Overtime: {overtime:f} {overtimePay:f}");
WriteLine("=======================================================");
WriteLine($" Net Pay: {weeklyPay:f}");
WriteLine("=======================================================");
}FUN DEPARTMENT STORE
=======================================================
Payroll Preparation
-------------------------------------------------------
Enter the following pieces of information
-------------------------------------------------------
Employee Information
-------------------------------------------------------
First Name: Jennifer
Last Name: Simms
Hourly Salary: 31.57
-------------------------------------------------------
Time worked
-------------------------------------------------------
Monday: 8
Tuesday: 8
Wednesday: 8
Thursday: 8
Friday: 8
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
FUN DEPARTMENT STORE
=======================================================
Payroll Evaluation
=======================================================
Employee Information
-------------------------------------------------------
Full Name: Jennifer Simms
Hourly Salary: 31.57
=======================================================
Time Worked Summary
--------+---------+-----------+----------+-------------
Monday | Tuesday | Wednesday | Thursday | Friday
--------+---------+-----------+----------+-------------
8.00 | 8.00 | 8.00 | 8.00 | 8.00
========+=========+===========+==========+=============
Pay Summary
-------------------------------------------------------
Time Pay
-------------------------------------------------------
Regular: 40.00 1262.80
-------------------------------------------------------
Overtime: 0.00 0.00
=======================================================
Net Pay: 1262.80
=======================================================
Press any key to close this window . . .A Read-Only Multidimensional Array
When you are creating an array in a class, if you are planning to initialize it in the class, you can (and should) mark the array as read-only. To do this, apply the readonly operator to the variable. This can be done as follows:
using static System.Console;
TriangleInCoordinateSystem tri = new TriangleInCoordinateSystem();
tri.ShowPoints();
Title = "Triangle Coordinates";
WriteLine("====================================");
public record class TriangleInCoordinateSystem
{
readonly int[,] points;
public TriangleInCoordinateSystem()
{
points = new int[3, 2];
points[0, 0] = -2; // A(x, )
points[0, 1] = -3; // A( , y)
points[1, 0] = 5; // B(x, )
points[1, 1] = 1; // B( , y)
points[2, 0] = 4; // C(x, )
points[2, 1] = -2; // C( , y)
}
public void ShowPoints()
{
string strCoordinates = "Coordinates of the Triangle" + Environment.NewLine +
"A(" + points[0, 0] + ", " + points[0, 1] + ")" + Environment.NewLine +
"B(" + points[1, 0] + ", " + points[1, 1] + ")" + Environment.NewLine +
"C(" + points[2, 0] + ", " + points[2, 1] + ")";
WriteLine(strCoordinates);
}
}
Of course, a null-bound array can be created as read-only:
using static System.Console;
TriangleInCoordinateSystem tri = new TriangleInCoordinateSystem();
tri.ShowPoints();
Title = "Triangle Coordinates";
WriteLine("====================================");
public record class TriangleInCoordinateSystem
{
private readonly int[,]? points;
public TriangleInCoordinateSystem()
{
points = new int[3, 2];
points[0, 0] = -2; // A(x, )
points[0, 1] = -3; // A( , y)
points[1, 0] = 5; // B(x, )
points[1, 1] = 1; // B( , y)
points[2, 0] = 4; // C(x, )
points[2, 1] = -2; // C( , y)
}
public void ShowPoints()
{
string strCoordinates = "Coordinates of the Triangle" + Environment.NewLine +
"A(" + points?[0, 0] + ", " + points?[0, 1] + ")" + Environment.NewLine +
"B(" + points?[1, 0] + ", " + points?1, 1] + ")" + Environment.NewLine +
"C(" + points?[2, 0] + ", " + points?[2, 1] + ")";
WriteLine(strCoordinates);
}
}
Passing a Multi-Dimensional Array by Reference
When passing a multi-dimensional array as argument, you can pass the array as a reference. This makes it possible for the method to modify the array and return it changed. If you want to indicate that the array is passed by reference, precede its data type in the parentheses by the the ref keyword. Here is an example:
using static System.Console; int[,] pts = new int[3, 2]; TriangleInCoordinateSystem tri = new TriangleInCoordinateSystem(ref pts); tri.ShowPoints(pts); Title = "Triangle Coordinates"; WriteLine("===================================="); internal record TriangleInCoordinateSystem { public TriangleInCoordinateSystem(ref int[,] points) { points = new int[3, 2]; points[0, 0] = -2; // A(x, ) points[0, 1] = -3; // A( , y) points[1, 0] = 5; // B(x, ) points[1, 1] = 1; // B( , y) points[2, 0] = 4; // C(x, ) points[2, 1] = -2; // C( , y) } public void ShowPoints(int[,] coords) { string strCoordinates = "Coordinates of the Triangle" + Environment.NewLine + "A(" + coords[0, 0] + ", " + coords[0, 1] + ")" + Environment.NewLine + "B(" + coords[1, 0] + ", " + coords[1, 1] + ")" + Environment.NewLine + "C(" + coords[2, 0] + ", " + coords[2, 1] + ")"; WriteLine(strCoordinates); } }
Passing an Array by Reference
When an array of objects is passed normally, when the method ends, the changes made to the array are kept. This demonstrates that an array of objects is passe by reference. If you want to indicate that you are passing the array by referrence, precede the data type of the parameter with the ref keyword. Here is an example:
using static System.Console; using static System.Environment; Title = "Geometry"; Triangle tri = new Triangle(); Coordinate[,] coords = new Coordinate[3, 2]; tri.Create(ref coords); tri.Identify(coords); WriteLine("================================="); public record struct Coordinate { public int X { get; set; } public int Y { get; set; } } internal record class Triangle { public void Create(ref Coordinate[,] points) { points[0, 0] = new Coordinate(); // Point A(x, y) points[0, 0].X = 4; // A(x, ) points[0, 0].Y = 1; // A( , y) points[1, 0] = new Coordinate(); // Point B(x, y) points[1, 0].X = -4; // B(x, ) points[1, 0].Y = -2; // B( , y) points[2, 0] = new Coordinate(); // Point C(x, y) points[2, 0].X = 2; // C(x, ) points[2, 0].Y = 5; // C( , y) } public void Identify(Coordinate[,] vertices) { string strTriangle = "Triangle Vertices: " + NewLine + "A(" + vertices[0, 0].X + ", " + vertices[0, 0].Y + "), B(" + vertices[1, 0].X + ", " + vertices[1, 0].Y + "), and C(" + vertices[2, 0].X + ", " + vertices[2, 0].Y + ")"; WriteLine(strTriangle); } }
This would produce:
Triangle Vertices: A(4, 1), B(-4, -2), and C(2, 5) ================================= Press any key to close this window . . .
A Structure to Only Read Values
Introduction
As seen with classes, a structure can have one or more fields that are marked as read-only. A structure also have other read-only characteristics that are not available in a class.
A Read-Only Field
As seen with clases, a structure can have a read-only field, in which case you would apply the readonly keyword to the field. After doing that, you should initialize that field in a (the) constructor(s) of the structure. After doing that, you can access the read-only field and its value, inside and outside the structure. Here is an example:
using static System.Console; Machine mach = new Machine(); mach.Model = "MKR45"; mach.ItemCode = 392_474; mach.Make = "MILLEPUNTI "; WriteLine("Sewing Others"); WriteLine("=============================="); WriteLine("Machine Characteristics"); WriteLine("------------------------------"); WriteLine("Item Code: {0}", mach.ItemCode); WriteLine("Make: {0}", mach.Make); WriteLine("Model: {0}", mach.Model); WriteLine("Power Source: {0}", mach.PowerSource); WriteLine("=============================="); mach = new Machine(947_582); mach.Model = "ST371HD"; mach.Make = "Brother"; WriteLine("Machine Characteristics"); WriteLine("------------------------------"); WriteLine("Item Code: {0}", mach.ItemCode); WriteLine("Make: {0}", mach.Make); WriteLine("Model: {0}", mach.Model); WriteLine("Power Source: {0}", mach.PowerSource); WriteLine("=============================="); internal struct Machine { private string? _id; private int _code; private string? _company; public readonly string? PowerSource; public Machine() { PowerSource = "Ac/Dc"; } public Machine(int code) { ItemCode = code; PowerSource = "Corded Electric"; } internal int ItemCode { get { return _code; } set { _code = value; } } internal string? Make { get { return _company; } set { _company = value; } } internal string? Model { get { return _id; } set { _id = value; } } }
This would produce:
Sewing Others ============================== Machine Characteristics ------------------------------ Item Code: 392474 Make: MILLEPUNTI Model: MKR45 Power Source: Ac/Dc ============================== Machine Characteristics ------------------------------ Item Code: 947582 Make: Brother Model: ST371HD Power Source: Corded Electric ============================== Press any key to close this window . . .
A Structure to Only Read Values
You may remember that when you are creating an object from a class or a structure, you can require the user (programmer) to specify the values of the object in the constructor. In this case, you can create a parameter for each property in a constructor of the class or structure. Here is an example:
using static System.Console; Machine mach = new Machine(368_374, "Singer", "4411", 148.79); WriteLine("Sewing Others"); WriteLine("=============================="); WriteLine("Machine Characteristics"); WriteLine("------------------------------"); WriteLine("Item Code: {0}", mach.ItemCode); WriteLine("Make: {0}", mach.Make); WriteLine("Model: {0}", mach.Model); WriteLine("Price: ${0}", mach.UnitPrice); WriteLine("=============================="); internal struct Machine { public Machine(int code, string make, string model, double price) { ItemCode = code; Make = make; Model = model; UnitPrice = price; } internal int ItemCode { get; } internal string? Make { get; } internal string? Model { get; } public double UnitPrice { get; } }
This would produce:
Sewing Others ============================== Machine Characteristics ------------------------------ Item Code: 368374 Make: Singer Model: 4411 Price: $148.79 ============================== Press any key to close this window . . .
Of course, to change the values of the object, the user can initialize the object with another instance that uses the new operator. This can be done as follows:
Machine mach = new Machine(368_374, "Singer", "4411", 148.79); WriteLine("Sewing Others"); WriteLine("=============================="); WriteLine("Machine Characteristics"); WriteLine("------------------------------"); WriteLine("Item Code: {0}", mach.ItemCode); WriteLine("Make: {0}", mach.Make); WriteLine("Model: {0}", mach.Model); WriteLine("Price: ${0}", mach.UnitPrice); WriteLine("=============================="); mach = new Machine(938_049, "ArtLak", "ArtLak", 58.68); WriteLine("Sewing Others"); WriteLine("=============================="); WriteLine("Machine Characteristics"); WriteLine("------------------------------"); WriteLine("Item Code: {0}", mach.ItemCode); WriteLine("Make: {0}", mach.Make); WriteLine("Model: {0}", mach.Model); WriteLine("Price: ${0}", mach.UnitPrice); WriteLine("==============================");
To reinforce this concept, you can create a read-only structure. To do this, when creating the structure, precede it with the readonly keyword.
using static System.Console;
Machine mach = new Machine(368_374, "Singer", "4411", 148.79);
WriteLine("Sewing Others");
WriteLine("==============================");
WriteLine("Machine Characteristics");
WriteLine("------------------------------");
WriteLine("Item Code: {0}", mach.ItemCode);
WriteLine("Make: {0}", mach.Make);
WriteLine("Model: {0}", mach.Model);
WriteLine("Price: ${0}", mach.UnitPrice);
WriteLine("==============================");
mach = new Machine(938_049, "ArtLak", "ArtLak", 58.68);
WriteLine("Sewing Others");
WriteLine("==============================");
WriteLine("Machine Characteristics");
WriteLine("------------------------------");
WriteLine("Item Code: {0}", mach.ItemCode);
WriteLine("Make: {0}", mach.Make);
WriteLine("Model: {0}", mach.Model);
WriteLine("Price: ${0}", mach.UnitPrice);
WriteLine("==============================");
internal readonly struct Machine
{
public Machine(int code, string make, string model, double price)
{
ItemCode = code;
Make = make;
Model = model;
UnitPrice = price;
}
internal int ItemCode
{
get;
}
internal string? Make
{
get;
}
internal string? Model
{
get;
}
public double UnitPrice
{
get;
}
}
This would produce:
Sewing Others ============================== Machine Characteristics ------------------------------ Item Code: 368374 Make: Singer Model: 4411 Price: $148.79 ============================== Sewing Others ============================== Machine Characteristics ------------------------------ Item Code: 938049 Make: ArtLak Model: ArtLak Price: $58.68 ============================== Press any key to close this window . . .
A Strucuture to Only Initialize
Since the above structure is a read-only type that requires the user to initialize the object directly in the constructor, you can as well add init clauses to reinforce the concept. This can be done as follows:
using static System.Console;
Machine mach = new Machine(938_074, "KPCB", "Serger", 172.25);
WriteLine("Sewing Others");
WriteLine("==============================");
WriteLine("Machine Characteristics");
WriteLine("------------------------------");
WriteLine("Item Code: {0}", mach.ItemCode);
WriteLine("Make: {0}", mach.Make);
WriteLine("Model: {0}", mach.Model);
WriteLine("Price: ${0}", mach.UnitPrice);
WriteLine("==============================");
internal readonly struct Machine
{
internal int ItemCode
{
get;
init;
}
internal string? Make
{
init;
get;
}
internal string? Model
{
get;
init;
}
public double UnitPrice
{
init;
get;
}
internal Machine(int code, string? make, string? model, double price)
{
ItemCode = code;
Make = make;
Model = model;
UnitPrice = price;
}
}
A Read-Only Clause in a Structure
We already learned how to create a complete property in a structure and how to access the property. Here is an example:
using static System.Console;
Road rd = new Road();
rd.Designation ="I90";
WriteLine("Road System Database");
WriteLine("====================");
WriteLine("Road Name: {0}", rd.Designation);
WriteLine("====================");
internal struct Road
{
private string? _name_;
public string? Designation
{
get
{
return _name_;
}
set
{
_name_ = value;
}
}
}
This would produce:
Road System Database ====================== Road Name: I90 ====================== Press any key to close this window . . .
Unlike a class, a structure can have a read-only property. To create such a property, when defining its get accessor, precede it with the readonly keyword. This can be done as follows:
using static System.Console;
Road rd = new Road();
rd.Designation ="I90";
WriteLine("Road System Database");
WriteLine("====================");
WriteLine("Road Name: {0}", rd.Designation);
WriteLine("====================");
internal struct Road
{
private string? _name_;
public string? Designation
{
readonly get
{
return _name_;
}
set
{
_name_ = value;
}
}
}
Of course, you can create an accessor that doesn't use a body. Here is an example:
internal struct Road
{
private string? _name_;
public string? Designation
{
get => _name_;
set
{
_name_ = value;
}
}
}
In this case, to indicate that the property should act as read-only, you can precede the get accessor with the readonly keyword. This can be done as follows:
internal struct Road
{
private string? _name_;
public string? Designation
{
readonly get => _name_;
set
{
_name_ = value;
}
}
}
An Automatic Property in a Structure
In the above example, we created a complete property that starts with a private field. Of course, a structure can have an automatic property. Here is an example:
using static System.Console;
Road rd = new Road();
rd.Designation ="I90";
WriteLine("Road System Database");
WriteLine("====================");
WriteLine("Road Name: {0}", rd.Designation);
WriteLine("====================");
internal struct Road
{
public string? Designation
{
get;
set;
}
}
If you create an automatic property in a structure, you can optionally precede the get accessor with the readonly keyword. This can be done as follows:
using static System.Console;
Road rd = new Road();
rd.Designation ="I90";
WriteLine("Road System Database");
WriteLine("====================");
WriteLine("Road Name: {0}", rd.Designation);
WriteLine("====================");
internal struct Road
{
public string? Designation
{
readonly get;
set;
}
}
We saw how to create a property that must be initialized with an object of a structure is created. We saw that such a property can be created with the init accessor. Here is an example:
using static System.Console;
Road rd = new Road("I90");
WriteLine("Road System Database");
WriteLine("====================");
WriteLine("Road Name: {0}", rd.Designation);
WriteLine("====================");
internal struct Road
{
public Road(string name)
{
Designation = name;
}
public string? Designation
{
get;
init;
}
}
If you create a property with the init accessor, to indicate that you want the property to be read-only, you can precede the data type of the property with the readonly keyword. This can be done as follows:
using static System.Console;
Road rd = new Road("I90");
WriteLine("Road System Database");
WriteLine("====================");
WriteLine("Road Name: {0}", rd.Designation);
WriteLine("====================");
internal struct Road
{
public Road(string name)
{
Designation = name;
}
public readonly string? Designation
{
get;
init;
}
}
========================================================================================
Structures and Functions or Methods
A Parameter of a Structure Type
You can create a parameter of a function or method and make that parameter a structure type. When calling the function or method, make sure you pass an appropriate object. Here is an example:
using static System.Console; Machine mach = new Machine(239_740, "Bernette", "b33", (16, 14, 8), 255.55); // Calling the function Present(mach); // Creating a parameter of a structure type void Present(Machine machine) { WriteLine("Sewing Others"); WriteLine("==========================================================="); WriteLine("Machine Characteristics"); WriteLine("-----------------------------------------------------------"); WriteLine("Item Code: {0}", machine.ItemCode); WriteLine("Make: {0}", machine.Make); WriteLine("Model: {0}", machine.Model); WriteLine("Dimensions (W x H x D): {0} inches x {1} inches x {2} inches", machine.Dimensions.width, machine.Dimensions.height, machine.Dimensions.depth); WriteLine("Price: ${0}", machine.UnitPrice); } WriteLine("==========================================================="); internal ref struct Machine { internal int ItemCode { get; init; } internal string? Make { init; get; } internal string? Model { get; init; } public double UnitPrice { init; get; } internal (int width, int height, int depth) Dimensions { get; init; } internal Machine(int code, string? make, string? model, (int width, int height, int depth) dim, double price) { (ItemCode, Make, Model, Dimensions, UnitPrice) = (code, make, model, dim, price); } }
Returning a Structured Object from a Function or Method
Like a regular data type or a class, a structure can serve as the return type of a function or a method. The rules are more related to those of a class. When creating the method, type the name of the structure on the left side of the name of the method. In the body of the method, implement the desired behavior. Before exiting the method, make sure you return a valid value that is of the type of the structure.
When a method returns a value of the type of a structure, you can assign the method call to a variable of the type of the structure. Here is an example:
using static System.Console; Machine Create() { Machine m = new Machine(239_740, "Bernette", "b33", (16, 14, 8), 255.55); return m; } void Present(Machine machine) { WriteLine("Sewing Others"); WriteLine("==========================================================="); WriteLine("Machine Characteristics"); WriteLine("-----------------------------------------------------------"); WriteLine("Item Code: {0}", machine.ItemCode); WriteLine("Make: {0}", machine.Make); WriteLine("Model: {0}", machine.Model); WriteLine("Dimensions (W x H x D): {0} inches x {1} inches x {2} inches", machine.Dimensions.width, machine.Dimensions.height, machine.Dimensions.depth); WriteLine("Price: ${0}", machine.UnitPrice); } Machine product = Create(); Present(product); WriteLine("==========================================================="); internal ref struct Machine { internal int ItemCode { get; init; } internal string? Make { init; get; } internal string? Model { get; init; } public double UnitPrice { init; get; } internal (int width, int height, int depth) Dimensions { get; init; } internal Machine(int code, string? make, string? model, (int width, int height, int depth) dim, double price) { (ItemCode, Make, Model, Dimensions, UnitPrice) = (code, make, model, dim, price); } }
Practical Learning: Using a Structure Object
using static System.Console; using RoadSystemDatabase; // Returning a structural object from a function Road Create() { Road rd = new Road(); rd.Distance = 232.406; rd.Designation = "US 36"; rd.RoadType = Category.USHighway; rd.End = "US-36 on CO-KS border"; rd.Start = "Deer Ridge - US 34"; return rd; } // Passing a structural object as argument void Show(object obj) { if (obj is null) return; Road rd = (Road)obj; WriteLine("Road System Database"); WriteLine("============================================"); WriteLine("Road Name: {0}", rd.Designation); WriteLine("Road Type: {0}", rd.RoadType); WriteLine("--------------------------------------------"); WriteLine("Start: {0}", rd.Start); WriteLine("End: {0}", rd.End); WriteLine("Length: {0:N} miles ({1:N} kilometers)", rd.Distance, rd.GetDistanceInKilometers()); WriteLine("============================================"); } Road rd = Create(); Show(rd);
Road System Database ============================================ Road Name: US 36 Road Type: USHighway -------------------------------------------- Start: Deer Ridge - US 34 End: US-36 on CO-KS border Length: 232.41 miles (374.01 kilometers) ============================================ Press any key to close this window . . .
Structures with Structures
Equating Two Structural Objects
A structure has some functionalities built in its type so taht you may not have to customize it.
Assigning an Object to Another
Imagine you create an object of a structure type. If you want a new object that uses the values of the first object, you can simply assign the first object to the new one, and both objects would have the same value. Here is an example that demonstrates it:
using static System.Console; Road I475 = new Road(); I475.Designation = "I-475"; I475.Distance = 15.83; // miles I475.Start = "Macon, Georgia"; I475.End = "near Bolingbroke"; WriteLine("Road System Database"); WriteLine("==========================="); WriteLine("Road Name: {0}", I475.Designation); WriteLine("Length: {0} miles", I475.Distance); WriteLine("Start: {0}", I475.Start); WriteLine("End: {0}", I475.End); WriteLine("==========================="); Road I75 = I475; WriteLine("Road Name: {0}", I75.Designation); WriteLine("Length: {0} miles", I75.Distance); WriteLine("Start: {0}", I75.Start); WriteLine("End: {0}", I75.End); WriteLine("==========================="); internal struct Road { private string? name; private double len; private string? ending; private string? beginning; public string? Designation { get { return name; } set { name = value; } } public double Distance { get { return len; } set { len = value; } } public string? Start { get { return beginning; } set { beginning = value; } } public string? End { get { return ending; } set { ending = value; } } }
This would produce:
Road System Database =========================== Road Name: I-475 Length: 15.83 miles Start: Macon, Georgia End: near Bolingbroke =========================== Road Name: I-475 Length: 15.83 miles Start: Macon, Georgia End: near Bolingbroke =========================== Press any key to close this window . . .
Introduction to Updating a Structural Object
As seen in the previous section, after assigning one object to another, both objects hold the same value. If necessary, you can change the value of any property of the second object. This operation would allow you to update the second object. This can be done as follows:
using static System.Console;
Road I475 = new Road();
I475.Designation = "I-475";
I475.Distance = 15.83; // miles
I475.Start = "Macon, Georgia";
I475.End = "Bolingbroke";
WriteLine("Road System Database");
WriteLine("==================================");
WriteLine("Road Name: {0}", I475.Designation);
WriteLine("Length: {0} miles", I475.Distance);
WriteLine("==================================");
Road I75 = I475; // with { Designation = "I-90" };
I75.Designation = "I-75";
I75.Distance = 355.11; // miles
WriteLine("Road Name: {0}", I75.Designation);
WriteLine("Length: {0} miles", I75.Distance);
WriteLine("==================================");
internal struct Road
{
. . .
}
This would produce:
Road System Database ================================== Road Name: I-475 Length: 15.83 miles ================================== Road Name: I-75 Length: 355.11 miles ================================== Press any key to close this window . . .
Updating a Structural Object With New Values
If you had previously created a structural object and initialized with the values of your choice, imagine that you want to create a new object but that shares some values with the primary object. In this case, you can ask the compiler to first apply the values of the primary object to the new object and then change only the values you want on the new object. To support this operation, the C# language provides a keyword named with. To start, declare a variable using a structure type and provide the desired values to its properties. Then declare a variable for the new object you want and assign the first object to it. After assigning the object, type with {};. Inside the curly bracket, type a name of a property of the structure and assign the desired value to it. Here is an example:
using static System.Console;
Road I475 = new Road();
I475.Designation = "I-475";
I475.Distance = 15.83; // miles
I475.Start = "Macon, Georgia";
I475.End = "Bolingbroke";
WriteLine("Road System Database");
WriteLine("==================================");
WriteLine("Road Name: {0}", I475.Designation);
WriteLine("Length: {0} miles", I475.Distance);
WriteLine("Start: {0}", I475.Start);
WriteLine("End: {0}", I475.End);
WriteLine("==================================");
Road I75 = I475 with { Designation = "I-75" };
WriteLine("Road Name: {0}", I75.Designation);
WriteLine("Length: {0} miles", I75.Distance);
WriteLine("Start: {0}", I75.Start);
WriteLine("End: {0}", I75.End);
WriteLine("==================================");
internal struct Road
{
. . .
}
This would produce:
Road System Database ================================== Road Name: I-475 Length: 15.83 miles Start: Macon, Georgia End: Bolingbroke ================================== Road Name: I-75 Length: 15.83 miles Start: Macon, Georgia End: Bolingbroke ================================== Press any key to close this window . . .
In the same way, you can change the values of many properties. To do that, in the curly brackets of with {};, type the name of each desired property and assign the appropriate value to it. Separate the assignments with comas. Here is an example:
using static System.Console;
Road I475 = new Road();
I475.Designation = "I-475";
I475.Distance = 15.83; // miles
I475.Start = "Macon, Georgia";
I475.End = "Bolingbroke";
WriteLine("Road System Database");
WriteLine("==================================");
WriteLine("Road Name: {0}", I475.Designation);
WriteLine("Length: {0} miles", I475.Distance);
WriteLine("Start: {0}", I475.Start);
WriteLine("End: {0}", I475.End);
WriteLine("==================================");
Road I75 = I475 with { Designation = "I-75", Distance = 355.11 };
WriteLine("Road Name: {0}", I75.Designation);
WriteLine("Length: {0} miles", I75.Distance);
WriteLine("Start: {0}", I75.Start);
WriteLine("End: {0}", I75.End);
WriteLine("==================================");
internal struct Road
{
. . .
}
Structures and Classes
A Field of a Structure Type
Once a structure exists, you can use it as a type. In a structure or a class, you can create a field that is of a structure type. There is nothing significant to do when declaring the variable. Probably the most important detail to keep in mind is that you must initialize the variable before using it. Here are examples:
using static System.Console;
Triangle tri = new Triangle();
WriteLine("Geometry");
WriteLine("=================================");
WriteLine("Triangle Characteristics");
WriteLine("---------------------------------");
tri.Present();
WriteLine("---------------------------------");
WriteLine("Distance 1: {0}", tri.Distance1);
WriteLine("Distance 2: {0}", tri.Distance2);
WriteLine("Distance 3: {0}", tri.Distance3);
WriteLine("=================================");
internal struct Point
{
internal int X { get; set; }
internal int Y { get; set; }
}
internal class Triangle
{
private Point point1;
private Point point2;
private Point point3;
internal Triangle()
{
point1 = new Point();
point1.X = 2;
point1.Y = 3;
point2 = new Point();
point2.X = 4;
point2.Y = 2;
point3 = new Point();
point3.X = 3;
point3.Y = 6;
}
public double Distance1
{
get
{
return Math.Sqrt( ((point2.X - point1.X) * (point2.X - point1.X)) +
((point2.Y - point1.Y) * (point2.Y - point1.Y)) );
}
}
public double Distance2
{
get
{
return Math.Sqrt( ((point3.X - point2.X) * (point3.X - point2.X)) +
((point3.Y - point2.Y) * (point3.Y - point2.Y)) );
}
}
public double Distance3
{
get
{
return Math.Sqrt( ((point1.X - point3.X) * (point1.X - point3.X)) +
((point1.Y - point3.Y) * (point1.Y - point3.Y)) );
}
}
public void Present()
{
WriteLine("Point A({0}, {1})", point1.X, point1.Y);
WriteLine("Point B({0}, {1})", point2.X, point2.Y);
WriteLine("Point C({0}, {1})", point3.X, point3.Y);
}
}
This would produce:
Geometry ================================= Triangle Characteristics --------------------------------- Point A(2, 3) Point B(4, 2) Point C(3, 6) --------------------------------- Distance 1: 2.23606797749979 Distance 2: 4.123105625617661 Distance 3: 3.1622776601683795 ================================= Press any key to close this window . . .
A Property of a Structure Type
In a structure or a class, you can create a property that is a structure type. The rules are the same we reviewed for creating a property of a class. Here are examples:
using static System.Console;
Triangle tri = new Triangle();
tri.A = new Point(0, 2);
tri.B = new Point(7, 1);
tri.C = new Point(1, -1);
WriteLine("Geometry");
WriteLine("=================================");
WriteLine("Triangle Characteristics");
WriteLine("---------------------------------");
tri.Present();
WriteLine("---------------------------------");
WriteLine("Distance 1: {0}", tri.Distance1);
WriteLine("Distance 2: {0}", tri.Distance2);
WriteLine("Distance 3: {0}", tri.Distance3);
WriteLine("=================================");
internal struct Point
{
internal int X { get; set; }
internal int Y { get; set; }
internal Point(int x, int y)
{
X = x;
Y = y;
}
}
internal class Triangle
{
private Point a;
private Point b;
private Point c;
// A property of a structure type
public Point A
{
get
{
return a;
}
set
{
a = value;
}
}
// A property of a structure type
public Point B
{
get
{
return b;
}
set
{
b = value;
}
}
// A property of a structure type
public Point C
{
get
{
return c;
}
set
{
c = value;
}
}
public double Distance1
{
get
{
return Math.Sqrt( ((B.X - A.X) * (B.X - A.X)) +
((B.Y - A.Y) * (B.Y - A.Y)) );
}
}
public double Distance2
{
get
{
return Math.Sqrt( ((C.X - B.X) * (C.X - B.X)) +
((C.Y - B.Y) * (C.Y - B.Y)) );
}
}
public double Distance3
{
get
{
return Math.Sqrt( ((A.X - C.X) * (A.X - C.X)) +
((A.Y - C.Y) * (A.Y - C.Y)) );
}
}
public void Present()
{
WriteLine("Point A({0}, {1})", A.X, A.Y);
WriteLine("Point B({0}, {1})", B.X, B.Y);
WriteLine("Point C({0}, {1})", C.X, C.Y);
}
}
public Road Road1 { get; set; }
public Road Road2 { get; set; }
public string InOrNear { get; set; }
public Intersection()
{
}
public Intersection(Road one, Road two, string position)
{
Road1 = one;
Road2 = two;
InOrNear = position;
}
}
After creating the property, you can use it as you see fit.
A structure is sealed from inheritance. This means that, when it comes to inheritance, a structure is subject to the following characteristics:
Structures and References
Passing a Structural Object by Reference
When you create a parameter in a method or a function and that parameter is a structure type, the technique is referred to as passing by value. A copy of the value of the structure is passed to the method or function. If the function or method modifies the argument, the original value would stay intact. If you want the function or method to modify the value of the structure, you can pass the argument by reference. You can do this using the (rules of the) ref keyword. Here is an example:
using static System.Console; void Create(ref Machine sew) { sew = new Machine(239_740, "Bernette", "b33", (16, 14, 8), 255.55); } void Present(Machine machine) { WriteLine("Sewing Others"); WriteLine("==========================================================="); WriteLine("Machine Characteristics"); WriteLine("-----------------------------------------------------------"); WriteLine("Item Code: {0}", machine.ItemCode); WriteLine("Make: {0}", machine.Make); WriteLine("Model: {0}", machine.Model); WriteLine("Dimensions (W x H x D): {0} inches x {1} inches x {2} inches", machine.Dimensions.width, machine.Dimensions.height, machine.Dimensions.depth); WriteLine("Price: ${0}", machine.UnitPrice); } Machine product = new(); Create(ref product); Present(product); WriteLine("==========================================================="); internal ref struct Machine { internal int ItemCode { get; init; } internal string? Make { init; get; } internal string? Model { get; init; } public double UnitPrice { init; get; } internal (int width, int height, int depth) Dimensions { get; init; } internal Machine(int code, string? make, string? model, (int width, int height, int depth) dim, double price) { (ItemCode, Make, Model, Dimensions, UnitPrice) = (code, make, model, dim, price); } }
You can also pass the referenced argument using the out keyword. Here is an example:
using static System.Console; void Create(out Machine sew) { sew = new Machine(239_740, "Bernette", "b33", (16, 14, 8), 255.55); } void Present(Machine machine) { WriteLine("Sewing Others"); WriteLine("==========================================================="); WriteLine("Machine Characteristics"); WriteLine("-----------------------------------------------------------"); WriteLine("Item Code: {0}", machine.ItemCode); WriteLine("Make: {0}", machine.Make); WriteLine("Model: {0}", machine.Model); WriteLine("Dimensions (W x H x D): {0} inches x {1} inches x {2} inches", machine.Dimensions.width, machine.Dimensions.height, machine.Dimensions.depth); WriteLine("Price: ${0}", machine.UnitPrice); } Machine product; Create(out product); Present(product); WriteLine("==========================================================="); internal ref struct Machine { internal int ItemCode { get; init; } internal string? Make { init; get; } internal string? Model { get; init; } public double UnitPrice { init; get; } internal (int width, int height, int depth) Dimensions { get; init; } internal Machine(int code, string? make, string? model, (int width, int height, int depth) dim, double price) { (ItemCode, Make, Model, Dimensions, UnitPrice) = (code, make, model, dim, price); } }
A Referenced Structure
When creating a structure, you can indicate to the compiler that you want the objects created from that structure to be treated as reference type. To do this, before the struct keyword, type the ref keyword. Here is an example:
using static System.Console;
Machine Create()
{
Machine m = new Machine((15.3, 12.0, 5.80), 162.88);
m.ItemCode = 293_749;
m.Model = "XR3774";
m.Make = "Brother";
return m;
}
void Present(Machine machine)
{
WriteLine("Sewing Others");
WriteLine("==============================================================");
WriteLine("Machine Characteristics");
WriteLine("--------------------------------------------------------------");
WriteLine("Item Code: {0}", machine.ItemCode);
WriteLine("Make: {0}", machine.Make);
WriteLine("Model: {0}", machine.Model);
WriteLine("Dimensions (W x H x D): {0} inches x {1} inches x {2} inches",
machine.Dimensions.width, machine.Dimensions.height, machine.Dimensions.depth);
WriteLine("Price: ${0}", machine.UnitPrice);
}
Machine product = Create();
Present(product);
WriteLine("==============================================================");
internal ref struct Machine
{
private string? _id;
private int _code;
private string? _company;
public Machine((double width, double height, double depth) dim, double price)
{
Dimensions = dim;
UnitPrice = price;
}
internal int ItemCode
{
get
{
return _code;
}
set
{
_code = value;
}
}
internal string? Make
{
get
{
return _company;
}
set
{
_company = value;
}
}
internal string? Model
{
get
{
return _id;
}
set
{
_id = value;
}
}
internal (double width, double height, double depth) Dimensions
{
get;
init;
}
public double UnitPrice
{
init;
get;
}
}
This would produce:
Sewing Others ============================================================== Machine Characteristics -------------------------------------------------------------- Item Code: 293749 Make: Brother Model: XR3774 Dimensions (W x H x D): 15.3 inches x 12 inches x 5.8 inches Price: $162.88 ============================================================== Press any key to close this window . . .
Notice that it is very simple to transform a regular structure into a referenced one. But once you apply that keyword, the structure becomes subject to new rules:
A Read-Only Referenced Structure
When creating a referenced structure, if you want the properties of the structure to be read-only, before the ref struct expression, type the readonly keyword. Here is an example:
// . . .
internal readonly ref struct Machine
{
// . . .
}
==================================================================================
Reading Only an Indexed Property
Introduction
We already know how to create an array, how to assign values to its elements, and how to get the value of each element. Here is an example:
Console.Title = "Numbers"; double[] numbers = new double[5]; numbers[0] = 927.93; numbers[1] = 45.155; numbers[2] = 2.37094; numbers[3] = 73475.25; numbers[4] = 186.72; Console.WriteLine("Numbers"); Console.WriteLine("--------------------"); for (int i = 0; i < numbers.Length; i++) Console.WriteLine("Number {0}: {1}", i + 1, numbers[i]); Console.WriteLine("=================================");
This would produce:
Numbers -------------------- Number 1: 927.93 Number 2: 45.155 Number 3: 2.37094 Number 4: 73475.25 Number 5: 186.72 ================================= Press any key to continue . . .
In the same way, if you create an array as a field of a class, to access an element of that member, you can use an instance of the class, followed by the period operator, followed by the member variable applied with the square brackets. Instead of accessing each element through its member variable, you can create a type of property referred to as an indexer.
An indexer, also called an indexed property, is a class's property that allows you to access a member variable of a class using the features of an array. To create an indexed property, start the class like any other. In the body of the class, create a field that is an array. Here is an example:
public class Number
{
double[] Numbers = new double[5];
}
In the body of the class, create a property named this with its accessor(s). The this property must be the same type as the field to which it will refer. The property must take a parameter as an array. This means that it must have square brackets. Inside the brackets, include the parameter you will use as index to access the members of the array.
Traditionally, and as we have seen so far, you usually access the members of an array using an integer-based index. Therefore, you can use an int type as the index of the array. Of course, the index's parameter must have a name, such as i. This would be done as follows:
public class Number
{
double[] Numbers = new double[5];
public double this[int i]
{
}
}
If you want the property to be read-only, include only a get accessor. In the get accessor, you should return an element of the array field to which the property refers, using the parameter of the property. This would be done as follows:
public class Number
{
double[] Numbers = new double[5];
public double this[int i]
{
get { return Numbers[i]; }
}
}
If necessary, you use a member of the class to initialize the array. Here is an example:
public class Number
{
double[] numbers = new double[5];
public double this[int i]
{
get { return numbers[i]; }
}
public Number()
{
numbers = new double[5];
numbers[0] = 927.93;
numbers[1] = 45.155;
numbers[2] = 2.37094;
numbers[3] = 73475.25;
numbers[4] = 186.72;
}
}
Based on this, a type of formula to create a normal read-only indexed property is:
class class-name { data-type[] array-name = new data-type[length]; public data-type this[int i] { get { return array-name[i]; } } }
Accessing an Element of an Indexed Property
Once you have created an indexed property, the class can be used. To start, you can declare a variable of the class. To access its arrayed field, you can apply the square brackets directly to the variable of the class. The variable would produce the value stored at that index. Here are examples:
Console.Title = "Numbers";
Console.WriteLine("Numbers");
Console.WriteLine("-----------------");
var number = new Number();
Console.WriteLine("Number: {0}", number[0]);
Console.WriteLine(string.Format("Number: {0}", number[2]));
Console.WriteLine($"Number: {number[4]}");
Console.WriteLine("=================================");
public class Number
{
double[] numbers = new double[5];
public double this[int i]
{
get { return numbers[i]; }
}
public Number()
{
numbers = new double[5];
numbers[0] = 927.93;
numbers[1] = 45.155;
numbers[2] = 2.37094;
numbers[3] = 73475.25;
numbers[4] = 186.72;
}
}
This would produce:
Numbers ----------------- Number: 927.93 Number: 2.37094 Number: 186.72 ================================= Press any key to continue . . .
Based on the known number of items of the array, you can use a loop (while, do...while or for) to access each element from its indexed property. Here is an example:
int i = 0; var number = new Number(); while (i < 3) { Console.WriteLine("Number {0}: {1}", i + 1, number[i]); i++; } Console.WriteLine("================================="); public class Number { double[] numbers = new double[5]; public double this[int i] { get { return numbers[i]; } } public Number() { numbers = new double[5]; numbers[0] = 927.93; numbers[1] = 45.155; numbers[2] = 2.37094; numbers[3] = 73475.25; numbers[4] = 186.72; } }
You can also use a foreach loop to visit each member of the property.
Remember, as we have already seen, that if you are providing the values of the array, you should make it read-only. This can be done as follows:
var number = new Number();
Console.WriteLine("Number: {0}", number[0]);
Console.WriteLine(string.Format("Number: {0}", number[2]));
Console.WriteLine($"Number: {number[4]}");
Console.WriteLine("=================================");
public class Number
{
readonly double[] numbers = new double[5];
public double this[int i]
{
get { return numbers[i]; }
}
public Number()
{
numbers = new double[5] { 927.93, 45.155, 2.37094, 73475.25, 186.72 };
}
}
A String-Based Indexed Property
Introduction to String-Based Indexed Properties
Usually when you create an array, to access an item, you use its index, which is normally based on an integer. When it comes to indexed properties, you can specify that the members of its array will be accessed through a string.
To create an indexed property where the members of its array can be accessed by a string, in the square brackets of the this property, pass the string as data type followed by a name for the parameter. Here is an example:
public class StudentAge
{
public float this[string name]
{
}
}
When defining the indexed property, there are two rules you must follow and you are aware of them already because an indexed property is like a method that takes a parameter and doesn't return void. When defining the indexed property, make sure you return the type of value that was used to declare the array. Here is an example:
public class StudentAge
{
public float this[string name]
{
get
{
if( name == "Ernestine Jonas" )
return 14.50f;
else if( name == "Paul Bertrand Yamaguchi" )
return 12.50f;
else if( name == "Helene Jonas" )
return 16.00f;
else if( name == "Chrissie Hanson" )
return 14.00f;
else if( name == "Bernard Hallo" )
return 15.50f;
else
return 12.00f;
}
}
}
Accessing a String-Based Indexed Property
Once you have defined the property, you can use it. To access any of its elements, you must pass a string to the square brackets as index. You can then do whatever you want with the value produced by the property, for example, you can display it to a visitor. Here is an example:
using static System.Console;
WriteLine("Students");
StudentAge sa = new StudentAge();
float age = sa["Paul Bertrand Yamaguchi"];
WriteLine("Student Age: {0}", age);
WriteLine("=================================");
public class StudentAge
{
public float this[string name]
{
get
{
if (name == "Ernestine Jonas")
return 14.50f;
else if (name == "Paul Bertrand Yamaguchi")
return 12.50f;
else if (name == "Helene Jonas")
return 16.00f;
else if (name == "Chrissie Hanson")
return 14.00f;
else if (name == "Bernard Hallo")
return 15.50f;
else
return 12.00f;
}
}
}
This would produce:
Students Student Age: 12.5 ================================= Press any key to continue . . .
Indexed Properties of Other Types
Introduction
When creating an indexed property, you will decide what type of value the property must produce or the type it can have. As opposed to an int or a double, you can also create a property that takes or produces a string. Here is an example:
public class Philosopher
{
string[] phil = new string[8];
public string this[int i]
{
get { return phil[i]; }
}
public Philosopher()
{
phil[0] = "Aristotle";
phil[1] = "Emmanuel Kant";
phil[2] = "Tom Huffman";
phil[3] = "Judith Jarvis Thompson";
phil[4] = "Thomas Hobbes";
phil[5] = "Cornell West";
phil[6] = "Jane English";
phil[7] = "James Rachels";
}
}
You can then use a variable of the class to access the indexed property. Here is an example:
Console.Title = "Philosophers";
Console.WriteLine("Philosophers");
var thinkers = new Philosopher();
Console.WriteLine("-------------------------------------");
for(int i = 0; i < 8; i++)
Console.WriteLine("Philosopher: {0}", thinkers[i]);
Console.WriteLine("======================================");
public class Philosopher
{
readonly string[] phil = new string[8];
public string this[int i]
{
get { return phil[i]; }
}
public Philosopher()
{
phil[0] = "Aristotle";
phil[1] = "Emmanuel Kant";
phil[2] = "Tom Huffman";
phil[3] = "Judith Jarvis Thompson";
phil[4] = "Thomas Hobbes";
phil[5] = "Cornell West";
phil[6] = "Jane English";
phil[7] = "James Rachels";
}
}
This would produce:
Philosophers ------------------------------------- Philosopher: Aristotle Philosopher: Emmanuel Kant Philosopher: Tom Huffman Philosopher: Judith Jarvis Thompson Philosopher: Thomas Hobbes Philosopher: Cornell West Philosopher: Jane English Philosopher: James Rachels ====================================== Press any key to continue . . .
In the same way, you can create a Boolean-based indexed property by simply making it return a bool type. You can then use a variable of the class as an array. Here is an example:
Console.Title = "Driving Record";
Console.WriteLine("Driving Record");
var driving = new DrivingWhileIntoxicated();
Console.WriteLine("-------------------------------------");
for (int i = 0; i < 7; i++)
Console.WriteLine("Driver Was Intoxicated {0}: {1}", i + 1, driving[i]);
Console.WriteLine("======================================");
public class DrivingWhileIntoxicated
{
readonly bool[] dwi = new bool[7];
public bool this[int i]
{
get { return dwi[i]; }
}
public DrivingWhileIntoxicated()
{
dwi[0] = false;
dwi[1] = true;
dwi[2] = true;
dwi[3] = false;
dwi[5] = false;
dwi[6] = false;
}
}
This would produce:
Driving Record ------------------------------------- Driver Was Intoxicated 1: False Driver Was Intoxicated 2: True Driver Was Intoxicated 3: True Driver Was Intoxicated 4: False Driver Was Intoxicated 5: False Driver Was Intoxicated 6: False Driver Was Intoxicated 7: False ====================================== Press any key to continue . . .
An Enumeration-Based Indexed Property
You can pass an enumeration as an index. To do this, after defining the enumeration, type its name and a parameter name in the square brackets of the this member, then define the property as you see fit. To access the property outside, apply an enumeration member to the square brackets on an instance of the class. Here is an example:
var mbr = new GolfClubMembership(); Console.WriteLine(string.Format("Membership Fee: {0}", mbr[CategoryFee.Senior])); public enum CategoryFee { Children, Adult, Senior, Unknown } public class GolfClubMembership { readonly double[] fee = new double[4]; public GolfClubMembership() { fee[0] = 150.95d; fee[1] = 250.75d; fee[2] = 85.65d; fee[3] = 350.00d; } public double this[CategoryFee cat] { get { if (cat == CategoryFee.Children) return fee[0]; else if (cat == CategoryFee.Adult) return fee[1]; else if (cat == CategoryFee.Senior) return fee[2]; else return fee[3]; } } }
This would produce:
Membership Fee: 85.65 Press any key to close this window . . .
Topics on Indexed Properties
Multi-Parameterized Indexed Properties
The indexed properties we have used so far were taking only one parameter. You can create an indexed property whose array uses more than one dimension. To start an indexed property that would use various parameters, first create the array. Then create a this property that takes the parameters. Here is an example for an indexed property that relates to a two-dimensional array:
public class Numbers
{
double[,] nbr;
public double this[int x, int y]
{
}
}
In the body of an accessor (get or set), use the parameter as appropriately as you see fit. At a minimum, for a get accessor, you can return the value of the array using the parameters based on the rules of a two-dimensional array. This can be done as follows:
public class Numbers
{
double[,] nbr;
public double this[int x, int y]
{
get { return nbr[x, y]; }
}
}
You can use a method of the class to initialize the array. Here is an example:
public class Numbers
{
readonly double[,] nbr;
public double this[int x, int y]
{
get { return nbr[x, y]; }
}
public Numbers()
{
nbr = new double[2, 4];
nbr[0, 0] = 927.93;
nbr[0, 1] = 45.155;
nbr[0, 2] = 2.37094;
nbr[0, 3] = 73475.25;
nbr[1, 0] = 186.72;
nbr[1, 1] = 82.350;
nbr[1, 2] = 712734.95;
nbr[1, 3] = 3249.0057;
}
}
After creating the property, you can access each element of the array by applying the square brackets to an instance of the class. Here is an example:
Console.WriteLine("Numbers");
var nbr = new Numbers();
Console.WriteLine("--------------------------");
for(int i = 0; i < 2; i++)
{
for (int j = 0; j < 4; j++)
{
double value = nbr[i, j];
Console.WriteLine("Number [{0}][{1}]: {2}", i, j, value);
}
}
Console.WriteLine("======================================");
public class Numbers
{
readonly double[,] nbr;
public double this[int x, int y]
{
get { return nbr[x, y]; }
}
public Numbers()
{
nbr = new double[2, 4];
nbr[0, 0] = 927.93;
nbr[0, 1] = 45.155;
nbr[0, 2] = 2.37094;
nbr[0, 3] = 73475.25;
nbr[1, 0] = 186.72;
nbr[1, 1] = 82.350;
nbr[1, 2] = 712734.95;
nbr[1, 3] = 3249.0057;
}
}
This would produce:
Numbers -------------------------- Number [0][0]: 927.93 Number [0][1]: 45.155 Number [0][2]: 2.37094 Number [0][3]: 73475.25 Number [1][0]: 186.72 Number [1][1]: 82.35 Number [1][2]: 712734.95 Number [1][3]: 3249.0057 ====================================== Press any key to continue . . .
Remember that one of the most valuable features of an indexed property is that, when creating it, you can make it return any primitive type and you can make it take any parameter of your choice. Also, the parameters of a multi-parameter indexed property don't have to be the same type. One can be a character while the other is a bool type, etc. When defining the property, you must apply the rules of both the methods and the arrays. Here is an example of a property that takes an integer and a string:
public class Catalog
{
readonly long[] nbrs;
readonly string[] names;
public double this[long nbr, string name]
{
get
{
if ((nbr == nbrs[0]) && (name == names[0]))
return 275.25;
else if ((nbr == nbrs[1]) && (name == names[1]))
return 18.75;
else if ((nbr == nbrs[2]) && (name == names[2]))
return 50.00;
else if ((nbr == nbrs[3]) && (name == names[3]))
return 65.35;
else if ((nbr == nbrs[4]) && (name == names[4]))
return 25.55;
else
return 0.00;
}
}
public Catalog()
{
nbrs = new long[5];
nbrs[0] = 273974;
nbrs[1] = 539759;
nbrs[2] = 710234;
nbrs[3] = 220685;
nbrs[4] = 192837;
names = new string[5];
names[0] = "Women Double-faced wool coat";
names[1] = "Men Cotton Polo Shirt";
names[2] = "Children Cable-knit Sweater";
names[3] = "Women Floral Silk Tank Blouse";
names[4] = "Girls Jeans with Heart Belt";
}
}
Here is an example that uses some variables:
using static System.Console;
var cat = new Catalog();
var itemNumber = 539759;
var itemDescription = "Men Cotton Polo Shirt";
var price = cat[itemNumber, itemDescription];
WriteLine("Item Number: " + itemNumber.ToString());
WriteLine("Description: " + itemDescription);
WriteLine("Unit Price: " + price.ToString("F"));
public class Catalog
{
readonly long[] nbrs;
readonly string[] names;
public double this[long nbr, string name]
{
get
{
if ((nbr == nbrs[0]) && (name == names[0]))
return 275.25;
else if ((nbr == nbrs[1]) && (name == names[1]))
return 18.75;
else if ((nbr == nbrs[2]) && (name == names[2]))
return 50.00;
else if ((nbr == nbrs[3]) && (name == names[3]))
return 65.35;
else if ((nbr == nbrs[4]) && (name == names[4]))
return 25.55;
else
return 0.00;
}
}
public Catalog()
{
nbrs = new long[5];
nbrs[0] = 273974;
nbrs[1] = 539759;
nbrs[2] = 710234;
nbrs[3] = 220685;
nbrs[4] = 192837;
names = new string[5];
names[0] = "Women Double-faced wool coat";
names[1] = "Men Cotton Polo Shirt";
names[2] = "Children Cable-knit Sweater";
names[3] = "Women Floral Silk Tank Blouse";
names[4] = "Girls Jeans with Heart Belt";
}
}
This would produce:
Item Number: 539759 Description: Men Cotton Polo Shirt Unit Price: 18.75 Press any key to close this window . . .
In the above example, we first declared the variables to be passed as parameters to the indexed property. You can pass such parameter(s) directly to a variable of the class. Here is an example:
var cat = new Catalog();
var price = cat[220685, "Women Floral Silk Tank Blouse"];;
Console.WriteLine("Unit Price: " + price.ToString("F"));
public class Catalog
{
readonly long[] nbrs;
readonly string[] names;
public double this[long nbr, string name]
{
get
{
if ((nbr == nbrs[0]) && (name == names[0]))
return 275.25;
else if ((nbr == nbrs[1]) && (name == names[1]))
return 18.75;
else if ((nbr == nbrs[2]) && (name == names[2]))
return 50.00;
else if ((nbr == nbrs[3]) && (name == names[3]))
return 65.35;
else if ((nbr == nbrs[4]) && (name == names[4]))
return 25.55;
else
return 0.00;
}
}
public Catalog()
{
nbrs = new long[5];
nbrs[0] = 273974;
nbrs[1] = 539759;
nbrs[2] = 710234;
nbrs[3] = 220685;
nbrs[4] = 192837;
names = new string[5];
names[0] = "Women Double-faced wool coat";
names[1] = "Men Cotton Polo Shirt";
names[2] = "Children Cable-knit Sweater";
names[3] = "Women Floral Silk Tank Blouse";
names[4] = "Girls Jeans with Heart Belt";
}
}
Just as you can create a two-dimensional indexed property, you can also create a property that takes more than two parameters. Once again, it is up to you to decide what type of parameter would be positioned where in the square brackets. Here is an example of an indexed property that takes three parameters:
public class Catalog
{
public string this[long nbr, string name, double price]
{
get
{
return "Item #: " + nbr.ToString() + ", " +
"Item Name: " + name + ", " +
"Unit Price: " + price.ToString("C");
}
}
}
To access the array stored in the class, after declaring a variable from it, pass the approriate values to its square brackets. Here is an example:
using static System.Console;
Title = "Department Store";
WriteLine("Department Store");
WriteLine("=================");
var cat = new Catalog();
WriteLine("Item Description");
WriteLine("------------------------------------------");
WriteLine(cat[220685, "Women Floral Silk Tank Blouse", 50.00]);
WriteLine("==========================================");
public class Catalog
{
public string this[long nbr, string name, double price]
{
get
{
return "Item #: " + nbr.ToString() + "\n" +
"Item Name: " + name + "\n" +
"Unit Price: " + price.ToString("C");
}
}
}
This would produce:
Department Store ================= Item Description ------------------------------------------ Item #: 220685 Item Name: Women Floral Silk Tank Blouse Unit Price: $50.00 ========================================== Press any key to continue . . .
Overloading an Indexed Property
An indexer borrows various characteristics of a method. One of them is the ability to create various indexers in the same class but all of them must have the same name: this. Still, the various indexers of a class can return the same type of value. Because of this, when creating the indexers, you must find a way to distinguish them. One way you can do this, as seen with method overloading, consists of passing a different type of parameter to each indexer. This is referred to as overloading.
To overload the this property, if two indexed properties take only one parameter, each must take a different (data) type of parameter than the other. Here is an example:
public class StudentIdentifications
{
readonly int[] studentIDs;
readonly string[] fullnames;
// This property takes a student ID, as an integer,
// and it produces his/her name
public string this[int id]
{
get
{
for (int i = 0; i < studentIDs.Length; i++)
if (id == studentIDs[i])
return fullnames[i];
return "Unknown Student";
}
}
// This property takes a student name, as a string,
// and it produces his/her student ID
public int this[string name]
{
get
{
for (int i = 0; i < fullnames.Length; i++)
if (name == fullnames[i])
return studentIDs[i];
return 0;
}
}
public StudentIdentifications()
{
studentIDs = new int[6];
studentIDs[0] = 39472;
studentIDs[1] = 13957;
studentIDs[2] = 73957;
studentIDs[3] = 97003;
studentIDs[4] = 28947;
studentIDs[5] = 97395;
fullnames = new string[6];
fullnames[0] = "Paul Bertrand Yamaguchi";
fullnames[1] = "Ernestine Ngovayang";
fullnames[2] = "Patricia L Katts";
fullnames[3] = "Helene Mukoko";
fullnames[4] = "Joan Ursula Hancock";
fullnames[5] = "Arlette Mimosa";
}
}
To access one of the properties, apply the square brackets to a variable of the class and pass the appropriate type(s) or number of properties. Here are examples:
using static System.Console;
Title = "Students Records";
WriteLine("Students Records");
WriteLine("==================================");
var std = new StudentIdentifications();
WriteLine("Student Identification");
WriteLine("----------------------");
WriteLine("Student ID: 39472");
WriteLine("Full Name: {0}", std[39472]);
WriteLine("===================================");
WriteLine("Student Identification");
WriteLine("----------------------");
WriteLine("Full Name: Joan Ursula Hancock");
WriteLine(string.Format("Student ID: {0}", std["Joan Ursula Hancock"]));
WriteLine("===================================");
public class StudentIdentifications
{
readonly int[] studentIDs;
readonly string[] fullnames;
// This property takes a student ID, as an integer,
// and it produces his/her name
public string this[int id]
{
get
{
for (int i = 0; i < studentIDs.Length; i++)
if (id == studentIDs[i])
return fullnames[i];
return "Unknown Student";
}
}
// This property takes a student name, as a string,
// and it produces his/her student ID
public int this[string name]
{
get
{
for (int i = 0; i < fullnames.Length; i++)
if (name == fullnames[i])
return studentIDs[i];
return 0;
}
}
public StudentIdentifications()
{
studentIDs = new int[6];
studentIDs[0] = 39472;
studentIDs[1] = 13957;
studentIDs[2] = 73957;
studentIDs[3] = 97003;
studentIDs[4] = 28947;
studentIDs[5] = 97395;
fullnames = new string[6];
fullnames[0] = "Paul Bertrand Yamaguchi";
fullnames[1] = "Ernestine Ngovayang";
fullnames[2] = "Patricia L Katts";
fullnames[3] = "Helene Mukoko";
fullnames[4] = "Joan Ursula Hancock";
fullnames[5] = "Arlette Mimosa";
}
}
This would produce:
Students Records ================================== Student Identification ---------------------- Student ID: 39472 Full Name: Paul Bertrand Yamaguchi =================================== Student Identification ---------------------- Full Name: Joan Ursula Hancock Student ID: 28947 =================================== Press any key to continue . . .
An indexer combines the features of an array and those of a method that takes one or more parameters. As an array, an indexer can use one or more dimensions as we have seen so far. Borrowing the features of a method, an indexer can take one or more parameters and it can return a value. Besides passing different types of parameters to various indexers, you can create some of them that take more than one parameter. To access the property, declare a variable of the class and pass the appropriate arguments to its square brackets. Here is an example:
using static System.Console;
Title = "Department Store";
WriteLine("Department Store");
WriteLine("========================================");
var cat = new Catalog();
WriteLine("Item Identification");
WriteLine("--------------------");
WriteLine("Item #: 539759");
WriteLine("Unit Price: {0}", cat[539759]);
WriteLine("========================================");
WriteLine("Item Identification");
WriteLine("--------------------");
WriteLine("Item #: 192837");
WriteLine("Description: Girls Jeans with Heart Belt");
WriteLine(string.Format("Unit Price: {0}", cat["Girls Jeans with Heart Belt", 192837]));
WriteLine("=========================================");
public class Catalog
{
readonly long[] nbrs;
readonly string[] names;
readonly double[] prices;
// This property produces the name of an item, as a string,
// if it is given the item #, as a number
public string this[long nbr]
{
get
{
for (int i = 0; i < nbrs.Length; i++)
if (nbr == nbrs[i])
return names[i];
return "Unknown Item";
}
}
// This property produces the price of the item, as a number,
// if it is given the item name and its number
public double this[string name, long nbr]
{
get
{
for (int i = 0; i < 5; i++)
if ((nbr == nbrs[i]) && (name == names[i]))
return prices[i];
return 0.00;
}
}
public Catalog()
{
nbrs = new long[5];
nbrs[0] = 273974;
nbrs[1] = 539759;
nbrs[2] = 710234;
nbrs[3] = 220685;
nbrs[4] = 192837;
names = new string[5];
names[0] = "Women Double-faced wool coat";
names[1] = "Men Cotton Polo Shirt";
names[2] = "Children Cable-knit Sweater";
names[3] = "Women Floral Silk Tank Blouse";
names[4] = "Girls Jeans with Heart Belt";
prices = new double[5];
prices[0] = 275.25;
prices[1] = 18.75;
prices[2] = 50.00;
prices[3] = 65.35;
prices[4] = 25.55;
}
}
This would produce:
Department Store ======================================== Item Identification -------------------- Item #: 539759 Unit Price: Men Cotton Polo Shirt ======================================== Item Identification -------------------- Item #: 192837 Description: Girls Jeans with Heart Belt Unit Price: 25.55 ========================================= Press any key to continue . . .
Read/Write Indexed Properties
Introduction
So far, we have purposely used indexed properties that only produced a value. In some cases, you may want to be able to specify the value of an element of the array. To make this possible, you can create an indexed property that uses an array whose values you can specify or change. Other than that, remember that a property that can accept and produce values is called a read-write property. If you want an indexed property to be read/write, besides the get accessor as we have been using it so far, you should also include a set accessor. |
![]() |
A Read/Write Property of a Primitive Type
To create a read/write indexed property, you should include a set accessor for the property. In the set accessor, assign the value contextual keyword to the field indexed with the this parameter. Here is an example of a read/write indexed property that includes a set accessor:
public class Number
{
double[] Numbers;
public double this[int i]
{
get { return numbers[i]; }
set { numbers[i] = value; }
}
}
After creating the read/write property, you can assign its values outside of the class. In other words, clients of the class can change the values of its elements. Remember that the advantage of an indexed property is that each element of the arrayed field can be accessed from the instance of the class by directly applying the square brackets and the (appropriate) index to it. Here is an example:
public class Number
{
private double[] Numbers = new double[5];
public double this[int i]
{
get { return Numbers[i]; }
set { Numbers[i] = value; }
}
}
To set the value of an item, access it by its index and assign the desired value to it. Here is an example:
Console.Title = "Numbers";
Console.WriteLine("Numbers");
var nbr = new Number();
nbr[2] = 2.37094;
Console.WriteLine("------------------");
for (int i = 0; i < 5; i++)
Console.WriteLine("Number {0}: {1}", i + 1, nbr[i]);
Console.WriteLine("==================================");
public class Number
{
readonly double[] Numbers = new double[5];
public double this[int i]
{
get { return Numbers[i]; }
set { Numbers[i] = value; }
}
}
This would produce:
Numbers ------------------ Number 1: 0 Number 2: 0 Number 3: 2.37094 Number 4: 0 Number 5: 0 ================================== Press any key to continue . . .
Based on this, a type of formula to create a regular read/write indexed property is:
class class-name
{
data-type[] array-name = new data-type[Index];
public data-type this[int i]
{
get { return array-name[i]; }
set { array-name[i] = value; }
}
}
We saw that the index of a property could be a value other than an integer-based. For example, we created an index that was a string type. Here is an example:
public class Philosopher
{
private string[] phil = new string[8];
public string this[int i]
{
get { return phil[i]; }
set { phil[i] = value; }
}
}
For such a property, if you make it read/write, you can assign its values outside of the class. Here is an example:
Console.Title = "Philosophers";
Console.WriteLine("Philosophers");
var thinker = new Philosopher();
thinker[5] = "Stuart Rachels";
Console.WriteLine("-----------------------------");
for (int i = 0; i < 8; i++)
Console.WriteLine("Philosopher: {0}", thinker[i]);
Console.WriteLine("==================================");
public class Philosopher
{
readonly string[] phil = new string[8];
public string this[int i]
{
get { return phil[i]; }
set { phil[i] = value; }
}
}
This would produce:
Philosophers ----------------------------- Philosopher: Philosopher: Philosopher: Philosopher: Philosopher: Philosopher: Stuart Rachels Philosopher: Philosopher: ================================== Press any key to continue . . .
The same rules would apply to a read/write indexed property that can receive Boolean or decimal values.
Introduction to Built-In Generic Interfaces and Classes
Overview
To assist you in creating generic classes, the .NET Framework provides a large library of generic interfaces. To assist you with various types of object, the .NET Framework provides a rich library of generic classes. The generic classes in the .NET Framework are extremely easy to use.
Enumerating a List
When using built-in classes, you will encounter some classes with a method named GetEnumerator. Normally, when you see a GetEnumerator() method, this means that its class is used to create or manage a list, such as an array. The immediate consequence is that you can use the foreach operator on the object (actually a list) of that class.
Spanning an Object
Introduction
To assist you in creating and controlling the memory area occupied by an array, the .NET Framework provides a built-in generic structure named Span
public readonly ref struct Span<T>
As is the case for practically all .NET Framework built-in classes, the Span<T> structure is really easy to use it. To start, declare a variable of type Span<T>. Pass the type of the array as the parameter type. To help you in initializaing the variable, the Span<T> structure is equipped with four constructors. The most common constructor takes an array as argument:
public Span (T[]? array);
Using this constructor, you can pass an array as argument. You can create an array directly in the parentheses of the constructor. Here is an example:
Span<double> numbers = new Span<double>( new double[]{ 12.44, 7.137, 525.38, 46.28, 2448.32, 75.496, 632.04 } );
An Item of the Array
After the above declaration, the variable is an array and you can use it as such. For example, you can access a member of the array using the square brackets. To support this operation, the Span<T> structure is equipped with a this property:
public ref T this[int index] { get; }
Here is an example:
using static System.Console;
Span<double> numbers = new Span<double>( new double[]{ 12.44, 7.137, 525.38, 46.28, 2448.32, 75.496, 632.04 } );
WriteLine("Number: " + numbers[3].ToString());
WriteLine("===========================");
This would produce:
Number: 46.28 =========================== Press any key to close this window . . .
The Size of an Array
Like the Array class, the Span<T> structure is equipped with a property named Length:
public int Length { get; }
Enumerating an Array
The Span<T> structure is equipped with a GetEnumerator() method:
public Span<T>.Enumerator GetEnumerator ();
As a result, you can use a foreach operator to scan a Span<T> list. Here is an example:
using static System.Console;
Span<double> numbers = new Span<double>( new double[]{ 12.44, 8304.68, 7.137, 525.38,
46.28, 2448.32, 75.496, 632.04 } );
foreach (double number in numbers)
{
WriteLine("Number: " + number.ToString());
}
WriteLine("===========================");
This would produce:
Number: 12.44 Number: 7.137 Number: 525.38 Number: 46.28 Number: 2448.32 Number: 75.496 Number: 632.04 =========================== Press any key to close this window . . .
Copying an Array
If you have an existing array and want to control how it is stored in memory, you can pass that array to a Span<T> variable. To perform this operation, you have two options. As one solution, you can pass the array variable to the above Span<T> constructor. This can be done as follows:
using static System.Console; double[] values = { 12.44, 8304.68, 7.137, 525.38, 46.28, 2448.32, 75.496, 632.04 }; Span<double> numbers = new Span<double>(values); foreach (double number in numbers) { WriteLine("Number: " + number.ToString()); } WriteLine("===========================");
Another solution is to directly assign an array to a Span<T> variable. This can be done as follows:
using static System.Console; double[] values = { 12.44, 8304.68, 7.137, 525.38, 46.28, 2448.32, 75.496, 632.04 }; Span<double> numbers = values; foreach (double number in numbers) { WriteLine("Number: " + number.ToString()); } WriteLine("===========================");
Slicing an Array
Slicing a list consists of creating a sub-list using a range of items from an existing list. To support this operation, the Span<T> structure is equipped with an overloaded method named Slice. One of the syntaxes of this method takes one integer argument:
public Span<T> Slice (int start);
This version specifies the index from which to start considering the members of the existing array. Another version takes two arguments:
public Span<T> Slice (int start, int length);
The first argument specifies from which index to start considering the items of the list. The second argument is the number of items from the starting index. Here is an example:
using static System.Console;
double[] values = { 12.44, 8304.68, 7.137, 525.38,
46.28, 2448.32, 75.496, 632.04 };
Span<double> numbers = values;
foreach (double number in numbers)
{
WriteLine("Number: " + number.ToString());
}
WriteLine("--------------------------");
Span<double> part = numbers.Slice(2, 4);
foreach (double number in part)
{
WriteLine("Number: " + number.ToString());
}
WriteLine("===========================");
This would produce:
Number: 12.44 Number: 8304.68 Number: 7.137 Number: 525.38 Number: 46.28 Number: 2448.32 Number: 75.496 Number: 632.04 -------------------------- Number: 7.137 Number: 525.38 Number: 46.28 Number: 2448.32 =========================== Press any key to close this window . . .
|
|
|||
| Previous | Copyright © 2001-2026, FunctionX | Sunday 03 May 2026, 19:58 | Next |
|
|
|||