Codechef4u is a community for computer professionals,by computer professionals,just like you; who loves sharing and helping each others,Join them
Share your post

Understanding event handling in c#

Understanding event handling in c#

What is event?

In simple English language event, some action or something to happen. 

In programming terms, it means that an object raises an event and another object or other objects handle the event.

Two types of objects communicate in event handling

1. object raises an event (Publisher)
2. objects handle the event (Subscribers)

How it works?

The object (publisher) that raises the event notifies the other objects (subscribers) that something has occurred so that the objects (subscribers) can do (handle) something on and with that event.

Delegate

Delegate is type that represents safe reference to methods with parameters list and return type.

Types (All three you can try with event handling and explained in detail with following codechef4u posts)


Events and delegates

Events and delegates are inextricably linked together, a delegate object can only refer to methods whose signature match the delegate’s.

EventHandler Delegate

Represents the method that will handle an event that has no event data.

public delegate void EventHandler(object? sender, EventArgs e); 
Object sender: The source of the event.
EventArgs e : An object that contains no event data.

In detail

.NET provides the EventHandler and EventHandler<TEventArgs> delegates to support most event scenarios. Use the EventHandler delegate for all events that do not include event data. Use the EventHandler<TEventArgs> delegate for events that include data about the event.

These delegates have no return type value and take two parameters (an object for the source of the event, and an object for event data).

C# Event Handler Example

Publisher class with eventhandler

//publisher class
   public class Logs
    {
        //Delegate use
        //public delegate void LogEventHandler(object source, LogEventArgs e);
        //event using delegate
        // public event LogEventHandler GenarateLog;
 
        public event EventHandler<LogEventArgs> GenarateLog;
        public void GenarateLogs(LogsData LogData)
        {
            Console.WriteLine("Generate logs");
            Thread.Sleep(3000);
 
            OnGenarateLog(LogData);
        }
        public virtual void OnGenarateLog(LogsData LogData)
        {
            //Legacy old invoke
            //if (GenarateLog != null)
            //{
            //    GenarateLog(this, new LogEventArgs() { LogsData = LogData });
            //}
 
            GenarateLog?.Invoke(this, new LogEventArgs() { LogsData = LogData });
        }
    }

 

Custom EventArgs implementation

//Custom event args
    public class LogEventArgs : EventArgs
    {
        public LogsData LogsData { get; set; }
    }

 

Subscriber classes

   //subscriber class 1 
    public class TextLogs
    {
        public void OnGenarateLog(object sender, LogEventArgs e)
        {
            Console.WriteLine("Generate text logs :"+e.LogsData.Title);
        }      }
 
    //subscriber class 2
    public class XmlLogs
    {
       public void OnGenarateLog(object sender, LogEventArgs e)
        {
            Console.WriteLine("Generate xml logs : "+e.LogsData.Title);
        }
    }

 

How to use it ?

class Program
    {
        static void Main(string[] args)
        {   
           //custom data instance
           LogsData logsData = new LogsData() { Title = "Event method" };
            //publisher instance
            var Logs = new Logs();
            //Text logs subscriber instance
            var textLogs = new TextLogs();
            //xml logs subscriber instance
            var xmlLogs = new XmlLogs();//xml logs subscriber
 
          //Events 
            Logs.GenarateLog += textLogs.OnGenarateLog;
            Logs.GenarateLog += xmlLogs.OnGenarateLog;
 
            Logs.GenarateLogs(logsData);
        }
    } 

Covariance and Contravariance in c#

Covariance and contravariance in generics and delegates

When you assign a method to a delegate, the method signature does not have to match the delegate exactly. This is called covariance and contravariance.

Covariance: It is related to method return types.

Enables you to use a more derived type than originally specified.

I.e You can assign an instance of IEnumerable<Derived> to a variable of type IEnumerable<Base>.

Contravariance: It is related to method parameter types.

Enables you to use a more generic (less derived) type than originally specified.

You can assign an instance of Action<Base> to a variable of type Action<Derived>.

Covariance and Contravariance c# simple example

 

  public class Employee
    {
        public string Name { get; set; }
    }
 
    public class ComtractEmployee : Employee { }
 
    public class MailingList
    {
        public void Add(IEnumerable<Employee> employee) {
 
            //some code
        }
    }
 
    public class Company
    {
        public IEnumerable<ComtractEmployee> GetContractEmployees() {
 
            var  empList = new List<ComtractEmployee>();
            //add some employee here n then return
            return empList;
        }
    }
 
    public class EmpNameComparer : IComparer<Employee>
    {
        public int Compare(Employee a, Employee b)
        {
            if (a == null) return b == null ? 0 : -1;
            return b == null ? 1 : Compare(a, b);
        }
 
        private int Compare(string a, string b)
        {
            if (a == null) return b == null ? 0 : -1;
            return b == null ? 1 : a.CompareTo(b);
        }
    }

 

class Program
    {
        static void Main(string[] args)
        {        
            //covariant use
            var Company = new Company();
            var Employees = Company.GetEmployees();
            var mailingList = new MailingList();
 
            // Add() is covariant here, we can use a more derived type
            mailingList.Add(Employees);
 
// the Set<T> constructor uses a contravariant interface, IComparer<in T>,
// we can use a more generic type than required.
var ContEmpSetSet = new SortedSet<ComtractEmployee>(Employees, new EmpNameComparer());
  }
}

Invariance

Means that you can use only the type originally specified. An invariant generic type parameter is neither covariant nor contravariant.

You cannot assign an instance of List<Base> to a variable of type List<Derived> or vice versa.

Generic Delegates in C#

Generic Delegates in C#

"Like generic classes and generic methods, a delegate can define its own type parameters"

Following example explained Generic delegate with type parameters. I. e delegate T SampleMatOperations<T>

Generic Delegate in C# with Real-Time Example

//Delegate declaration
public delegate T SampleMathOperations<T>(T x, T y);

//Math operations class 
public class MathOperations
    {
        public int Addition(int x,int y)
        {
            return x + y;
        }
 
        public int Subtract(int a,int b)
        {
            return a - b;
        }
    }


Create instance and invoke generic delegate

class Program
    {
        static void Main(string[] args)
        {
            int a = 50;int b = 75;
            var matOpObject = new MathOperations();
 
            //Generic delegate instance
            //additions
            SampleMathOperations<int> mathOperations = new SampleMathOperations<int>(matOpObject.Addition);
            //invoke 
            Console.WriteLine("Add  result on two numbers"
               + mathOperations(a, b));
 
            //subtraction (multicast delegate)
            mathOperations += matOpObject.Subtract;
            //invoke 
            Console.WriteLine("Sub result on two numbers"
               + mathOperations(a, b));
        }
    }


Inbuilt generic delegates

Microsoft provided three inbuilt generic delegates delegates introduced in C# 3 “System namespace”, those are Func, Action, and Predicate.
All these three delegates can be used with the method, anonymous method, and lambda expressions.

Func generic delegate in C#

When to use?

“Whenever delegates return some value with optional input parameters. i.e C# method with return value”

Description

This delegate takes one or more input parameters and returns one out parameter. The last parameter is considered as the return value.

It can take up to 16 input parameters of different types and those are optional, it must have one return type that is mandatory.

Action generic delegate in C#

When to use?

“Whenever delegates do not return any value with optional input parameters. i.e. C# method with void return value”

Description

It takes one or more input parameters and returns nothing.

This delegate can take a maximum of 16 input parameters of the different or same type.

Predicate Generic Delegate in C#

When to use?

“Whenever delegates return a Boolean value with optional input parameters. i.e. C# method with Boolean return value”

Description

It takes one input parameter and always returns a Boolean value which is mandatory.

This delegate can take a maximum of 1 input parameter and always return the value of the Boolean type.


Inbuilt Generic Delegates in C# with Real-Time Examples

Sample C# class with methods

public class GenericDelegatesSample
    {
        public int Addition(int x, int y)
        {
            return x + y;
        }
 
        public bool IsValidNumber(int x)
        {
            return x > 0 ? true : false;
        }
 
        public void DisplayResult(int x,int y)
        {
            var result = Addition(x, y);
            Console.WriteLine("Addition is :" + result);
        }
    }


Create instance of Inbuilt Generic delegates and invoke

class Program
    {
        static void Main(string[] args)
        {
            int a = 50;int b = 75;
            var opObject = new GenericDelegatesSample();
           
            //Func generic delegate
            Func<int, int, int> add = opObject.Addition;
            //invoke
            Console.WriteLine("Display result :" + add(a,b));
           
            //Action generic delegate
            Action<int, int> displayResult = opObject.DisplayResult;
            //invoke             displayResult(a, b);
 
            //Predicate generic delegate
            Predicate<int> isValidNum = opObject.IsValidNumber;
            //invoke
            Console.WriteLine("is valid number:" + isValidNum(a));
        }
    }