Objectives of this Exercise
This exercise introduces you to
- Property syntax
- Raising events
- Expression lambdas as event handlers
Video Explanation (see it happen!)
Please watch the following youtube video:
The Solution
Create a C# .NET Core console project as usual. Add a class called MyNumber. You can obtain the completed project from the downloads attached to this video. Now I will discuss the class.
First we have to add an event delegate that accepts one Int32 type of argument and returns void. We have already learnt that dotnet core provides a built-in Action<T> delegate that accepts one argument and returns a void. So we can define a public event called, let's say, public event Action
An Action delegate is usually not used for event handlers.
It is more appropriate to use built-in delegates like EventHandler
. These delegates contain a parameter to contain the sender of the event. The EventHandler<T>
delegate is different from an Action<T>
delegate only in the sender parameter void EventHandler<TEventArgs>(object? sender, TEventArgs e);
So let's add a data member for the event delegate and call it NumberChanged.
The event keyword signifies that it is a multicast delegate. Many multiple subscribers can subscribe to this delegate. All delegates will be notified when the event is raised. We will be later adding a subscriber in the Main function.
// mynumber.cs // project is in the attached downloads internal class MyNumber { public event EventHandler<Int32>? NumberChanged; private Int32 _number; public Int32 Number { get => _number; set { if (_number != value) { _number = value; // ?. null conditional operator // is a safety guard. Invoke is not // called if NumberChanged is null NumberChanged?.Invoke(this, _number); } } } }
Next we add a backing member for the Number property.
The getter for the property returns _number
.
The setter for the property sets _number = value, if there is a change.
The event is raised by a call to Invoke. The first argument is sender and the second the new number. The question mark after NumberChanged? means that Invoke will not be called if NumberChanged is null, which happens if there is no subscriber for this event.
Main in Program.cs
Next open the Program.cs file. Let's study the Main function now!
First of all we have created an object of the MyNumber class.
// program.cs file MyNumber mn = new(); // attach anonymous function // using expression lambda mn.NumberChanged += (s, n) => Console.WriteLine($"num = {n}"); Console.Write("Enter number: "); mn.Number = Int32.Parse(Console.ReadLine() ?? "0");
The NumberChanged event is subscribed by using the += operator. The handler is an expression lambda. The first argument s is the sender and the second n is the changed value. This function gets called when the NumberChanged event is raised by the MyNumber class.
Run the Project
We can now run the project. It asks to enter a number. When a number is entered it prints the new value through the attached event handler.
Another Example
Study this class.
internal class MyNumber
{
public event PropertyChangedEventHandler? PropertyChanged;
private UInt32 _number;
private UInt16 _lowPart;
private UInt16 _highPart;
private static UInt32 makeUInt32(UInt16 l, UInt16 h)
{
byte[] lowBytes = BitConverter.GetBytes(l);
byte[] highBytes = BitConverter.GetBytes(h);
byte[] numBytes = lowBytes.Concat(highBytes).ToArray();
return BitConverter.ToUInt32(numBytes, 0);
}
public UInt16 LowPart
{
get => _lowPart;
set
{
if (_lowPart != value)
{
Number = makeUInt32(value, _highPart);
}
}
}
public UInt16 HighPart
{
get => _highPart;
set
{
if (_highPart != value)
{
Number = makeUInt32(_lowPart, value);
}
}
}
public UInt32 Number
{
get => _number;
set
{
if (_number != value)
{
_number = value;
byte[] numBytes = BitConverter.GetBytes(_number);
_lowPart = BitConverter.ToUInt16(numBytes, 0);
_highPart = BitConverter.ToUInt16(numBytes, 2);
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs("Number Changed!"));
}
}
}
}
This is the main function.
// program.cs MyNumber mn = new(); Console.Write("Enter number: "); mn.Number = UInt32.Parse( Console.ReadLine() ?? "0");
This Blog Post/Article "(C# Language) Practice Exercise on Property changed event and Lambdas" by Parveen is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.