Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Saturday, July 22, 2023

Mediator Design Pattern


Mediator is an object that mediates between other objects to allow communication between them. Without mediator these objects will have to communicate directly. Let there be Sales and Marketing teams which want to communicate. They can send message from one to another using Send method.
void Send(string to, string from, string message);
Mediator design pattern is useful when multiple services are consumed by client classes in a uniform way.
We see the below example which is without Mediator Design Pattern. It will be converted into Mediator Design Pattern.
CASE1. Without Mediator Design Pattern
Create a console application in Visual Studio. Add a class file named as Team.cs Write the following code in it.
using System;

namespace MediatorDesignPattern
{
    public class Sales
    {
        public string Name { get; set; }
        public void Send(string to, string from, string message)
        {
            Console.WriteLine($"{message} sent from {from} to {to}");
        }
    }

    public class Marketing
    {
        public string Name { get; set; }
        public void Send(string to, string from, string message)
        {
            Console.WriteLine($"{message} sent from {from} to {to}");
        }
    }
}

In Program.cs, create the objects of the Sales and Marketing and invoke their Send methods.

namespace MediatorDesignPattern
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Sales t1 = new Sales();
            Marketing t2 = new Marketing();
            t1.Name = "Sales";
            t2.Name = "Marketing";
            t1.Send(t1.Name, t2.Name,"MessageX");
            t2.Send(t2.Name, t1.Name,"MessageY");
        }
    }
}

Run the app. We get the following message.
MessageX sent from Marketing to Sales
MessageY sent from Sales to Marketing

Next, update the code in Team.cs file as given below. Club the Sales and Marketing classes into Team class. The Team is abstract class which is inherited by them.

using System;

namespace MediatorDesignPattern
{
    public abstract class Team
    {
        public abstract string Name { get; set; }
        public abstract void Send(string to, string from, string message);
    }
    public class Sales : Team
    {
        public override string Name { get; set; }
        public override void Send(string to, string from, string message)
        {
            Console.WriteLine($"{message} sent from {from} to {to}");
        }
    }

    public class Marketing : Team
    {
        public override string Name { get; set; }
        public override void Send(string to, string from, string message)
        {
            Console.WriteLine($"This message '{ message}' sent from {from} to {to}");
        }
    }
}
Program.cs is as before.
namespace MediatorDesignPattern
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Sales t1 = new Sales();
            Marketing t2 = new Marketing();
            t1.Name = "Sales";
            t2.Name = "Marketing";
            t1.Send(t1.Name, t2.Name,"MessageX");
            t2.Send(t2.Name, t1.Name,"MessageY");
        }
    }
}

Run the app. We get the following message as before.
MessageX sent from Marketing to Sales
MessageY sent from Sales to Marketing

IMPORTANT: Here both Sales and Marketing teams are using their own Send method ( as they are overriding the abstract Send method in their own way)
But it is possible that there will be a mediator interface with Send method which is implemented uniformly by a mediator class. This class is used by both Sales and Marketing teams. Now, Send method is part of mediator and both Sales and Marketing use it. For this purpose, we create an interface named as IMediatorTeam which will be implemented by MediatorTeam class. Look at the following further updated code.
CASE2. With Mediator Design Pattern
Interface.
namespace MediatorDesignPattern
{
    internal interface IMediatorTeam
    {
        void SendMessage(string to, string from, string message);
    }
}
Implementation.

using System;

namespace MediatorDesignPattern
{
    public class MediatorTeam : IMediatorTeam
    {
        public void SendMessage(string to, string from, string message)
        {
            Console.WriteLine($"The '{message}' is sent from {from} to {to} via mediator.");
        }
    }
}
Update Team class. Both Sales and Marketing classes have MediatorTeam as property so that each class can use the method of MediatorTeam.

namespace MediatorDesignPattern
{
    public abstract class Team
    {
        public abstract string Name { get; set; }
        public abstract MediatorTeam Mediator { get; set; }
        public abstract void Send(string to, string from, string message);
    }
    public class Sales : Team
    {
        public override string Name { get; set; }
        public override MediatorTeam Mediator { get; set; }
        public override void Send(string to, string from, string message)
        {
            Mediator.SendMessage("Marketing", "Sales", "SALE 2023");
        }
    }
    public class Marketing : Team
    {
        public override string Name { get; set; }
        public MediatorTeam Mediator { get; set; }
        public override void Send(string to, string from, string message)
        {
            Mediator.SendMessage("Sales", "Marketing", "BOOM in market");
        }
    }
}
In Program.cs
namespace MediatorDesignPattern
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Sales t1 = new Sales();
            Marketing t2 = new Marketing();
            MediatorTeam mediatorTeam = new MediatorTeam();
            t1.Name = "Sales";
            t2.Name = "Marketing";
            t1.Send(t1.Name, t2.Name,"MessageX");
            t2.Send(t2.Name, t1.Name,"MessageY");
        }
    }
}
Run the app.
We get exception.
System.NullReferenceException: 'Object reference not set to an instance of an object.'
MediatorDesignPattern.Sales.Mediator.get returned null.

To remove this error, we initialize the MediatorTeam. Since MediatorTeam is a property of Sales and Marketing, we initialize this property in MediatorTeam.
IMediator Interface

namespace MediatorDesignPattern
{
    internal interface IMediatorTeam
    {
        void Register(Team member);
        void SendMessage(string to, string from, string message);
    }
}

Mediator class. Note that in the Register method team member is initialized.

using System;
using System.Collections.Generic;
using System.Linq;

namespace MediatorDesignPattern
{
    public class MediatorTeam : IMediatorTeam
    {
        private List _teams = new List();
        public void Register(Team member)
        {
            _teams.Add(member);
            member.Mediator=this;  // initialize
        }
        public void SendMessage(string to, string from, string message)
        {
            Team team = _teams.Where(t => t.Name == to)
            .First();
            if (team != null)
            {
                Console.WriteLine($"The message '{message}' is sent from {from} to {to} via mediator.");
            }
        }
    }
}
Team class is same as before.

namespace MediatorDesignPattern
{
    public abstract class Team
    {
        public abstract string Name { get; set; }
        public abstract MediatorTeam Mediator { get; set; }
        public abstract void Send(string to, string from, string message);
    }
    public class Sales : Team
    {
        public override string Name { get; set; }
        public override MediatorTeam Mediator { get; set; }
        public override void Send(string to, string from, string message)
        {
            Mediator.SendMessage("Marketing", "Sales", "SALE 2023");
        }
    }
    public class Marketing : Team
    {
        public override string Name { get; set; }
        public override MediatorTeam Mediator { get; set; }
        public override void Send(string to, string from, string message)
        {
            Mediator.SendMessage("Sales", "Marketing", "BOOM in market");
        }
    }
}
In Program.cs We use Register method.

namespace MediatorDesignPattern
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Sales t1 = new Sales();
            Marketing t2 = new Marketing();
            MediatorTeam mediatorTeam = new MediatorTeam();
            t1.Name = "Sales";
            t2.Name = "Marketing";
            mediatorTeam.Register(t1);
            mediatorTeam.Register(t2);
            t1.Send(t1.Name, t2.Name,"MessageX");
            t2.Send(t2.Name, t1.Name,"MessageY");
        }
    }
}

Note: Creating mediator class is not enough. We must have a method in mediator class which registers the types which will use the mediator class. For this we use Register method in the above example. We could also have used Deregister method to remove a type from the mediator class.

Friday, July 14, 2023

How to create attributes and Apply attributes in .NET


Steps to create a custom attribute class

  • Create a public class which derives from System.Attribute class. The name of class should suffix with Attribute word but it is not mandatory.
  • Apply the AttributeUsage attribute on this custom attribute class so that scope of the custom class on the target class is defined. The target class is the class which uses the custom attribute class.
  • To define the custom attribute class, you can use fields, properties and constructors in it like any other class.
  • To apply this custom attribute class in target class, create an instance of the custom attribute class in target class. 
  • For this, use Attribute.GetCustomAttribute method in the target class. There are many overloaded version of this method. It will return an instance of the custom attribute class. Check that the instance is not null. If it is not null, get all its properties and methods using dot operator.

EXAMPLE1: Create a custom attribute class which is used to display all the methods of a target class, when the attribute is applied on the target class.

STEP1. Create custom attribute class named as DisplayMethodsAttribute 

using System;
using System.Reflection;

namespace ConsoleApp1.AttributeDemo2
{
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
    public class DisplayMethodsAttribute : System.Attribute
    {
        public void DisplayMethods(Type classType)
        {
            MethodInfo[] methods = classType.GetMethods();
            for (int i = 0; i < methods.Length; i++)
            {
                Console.WriteLine($"method {i+1} is {methods[i].Name} in {classType.Name}");
            }
        }
    }
}
 

STEP2. Create target class named as Test. You can create n number of target classes.


using System;

namespace ConsoleApp1.AttributeDemo2
{
    [DisplayMethods()] // to list all the methods of this class in console
    public  class Test
    {
        public void Display()
        {
            Console.WriteLine("Test method1: Display");
        }

        public void Show()
        {
            Console.WriteLine("Test method2: Show");
        }

        public static void Run()
        {
            DisplayMethodsAttribute attr = (DisplayMethodsAttribute)Attribute.GetCustomAttribute(typeof(Test), typeof(DisplayMethodsAttribute));

            if (attr == null)
            {
                Console.WriteLine("DisplayMethodsAttribute is NULL");
            }
            else
            {
                //Console.WriteLine(attr.Company + " is located at " + attr.Location);
                attr.DisplayMethods(typeof(Test));
            }
        }
    }
}

STEP3. Run the application by using target class in any other client class.


using ConsoleApp1.AttributeDemo2;

namespace ConsoleApp1
{

    public class Program
    {
        public static void Main()
        {
            Test.Run();
        }
    }
}
 

EXAMPLE2: Example of Application of Attribute in ASP.NET Core Application

Create web project using ASP.NET Core Web App (Model-View-Controller) template.

STEP1. Create a custom attribute class as given below.


using System;

namespace WebApplicationRP
{
    // this attribute initializes the property IsOddHour as per condition
    // when this class is initialized in target method
    // We apply this attribute on a method
    [AttributeUsage(AttributeTargets.Method, Inherited =false, AllowMultiple =false)]
    public class OddHoursAttribute : Attribute
    {
        public bool IsOddHour { get; set; }
        public OddHoursAttribute()
        {
                int hour = DateTime.Now.Hour;
                IsOddHour = hour > 20 && hour < 24 ;
        }
    }
}

STEP2. Apply the custom attribute on action method of HomeController


using Microsoft.AspNetCore.Mvc;

namespace WebApplicationRP.Controllers
{
    public class HomeController : Controller
    {
        [OddHours]
        public IActionResult Index()
        {
            return View();
        }
    }
}

STEP3. In Startup class, expose the metadata of the custom class attribute in the middleware inserted between enable routing and use endpoints. In odd hours, the custom attribute on action method redirects to google server home page.


using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace WebApplicationRP
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddRazorPages();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            
            app.UseRouting();
            
            // middleware inserted between routing and endpoints
            app.Use(async (context, next) =>
            {
                var endpoint = context.GetEndpoint();
                if (endpoint != null)
                {
                    var oddhour = endpoint.Metadata.GetMetadata<OddHoursAttribute>();
                    if (oddhour != null && oddhour.IsOddHour)
                    {
                        //context.Response.WriteAsync("This is odd hour for this endpoint");
                        // URL must be valid. www.google.com not work
                        context.Response.Redirect("https://www.google.com");
                    }
                }
                await next();
            });

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute
                (
                name: "Defaults",
                pattern: "/{controller}/{action}/{id?}",
                defaults: new { controller = "Home", action = "Index" }
                );

            });
        }
    }
}

STEP4. Index View is displayed in not odd hours.


<h1>The current time @DateTime.Now.ToLongTimeString()</h1>

Updated on 13 July 2023

Monday, July 10, 2023

C# Event, Publisher and Subscriber classes

In this post, we will learn about Event. As the concept of event is closely related with delegate, the understanding of delegate is pre-requisite. Please go through Delegate post before going ahead this post.

What is an event?

An event is a way to send message from an object to another object to signal the occurrence of an action by the former object. In event, two objects sender and receiver of message or notification are involved. They are also known as publisher and subscriber objects.

We already know that delegate can be used to send the message from one object to another. Event is another way to do the same. Delegate works as a pipeline/medium to pass the message/data from sender to receiver. Delegate wraps the method which is to be executed when event is raised.

Before using event to send message from one object to another, we see how message can be propagated using delegate. Thereafter, we will see how the same can be done using Event.

Using Delegate Instead of Event for Notification

Create a console project in Visual Studio. Create Button class. Let’s suppose that we have Button class which has some events like click, double click etc.

Assume that for click event, we create a delegate so that when button is clicked, data will be sent from Button class to the subscriber class. It means that delegate will act as a medium or pipeline to pass data from Button class to Program class. In this example, Program class will be subscriber or receiver class.

Look at the following code in Button class.

public delegate void ClickDel(string message); //Step1
class Button
{
    public ClickDel click; // Step2
    public void ClickEventRaiser() // Step3
    {
        OnClick(); // Step4
    }

    private void OnClick()
    {
        if (click != null) // Step5
        {
            var data = "Some message from Button";
            click.Invoke(data); // Step6
        }
    }
}

Step1: We create a delegate which can be used to invoke any method which takes one string type parameter and returns void. This delegate will be used to send message from Button class to any other class. Publisher uses delegate to notify subscriber. In forthcoming paragraphs, we will see how instead of delegate event can be used for notification to subscriber classes.

Step2:  The click is delegate type reference variable. Note that delegate ClickDel is a type and so it is good convention to define it separately outside a class. So, we have defined it outside Button class. Please note that delegate is not initialized yet in Button class.

Step3: We have defined ClickEventRaiser method which will do some work and will raise event inside its body. When event (e.g. click) is raised - what will happen- its logic should be written in a separate method.

Step4: The logic of event (on click) is called. Note that on calling this method, event will be raised.

Step5: This step is crucial. It checks whether click delegate declared in Step2 is initialized or not. What it means? It means whether click delegate is subscribed in client Program class or not. This step will become clear when we look at Program class code. This step is linking publisher class to subscriber class. We will show how publisher class event (e.g. click) is subscribed by client class.

Step6: This step is also crucial. It shows that click delegate is invoked and message/data is sent using argument. We have initialized data inside OnClick method. We could have passed data from ClickEventRaiser method as well. I have avoided this to avoid confusion for beginners. We just have to remember that delegate is invoked inside the method which is called when event is raised.

Now, look at the following code in Program class. Program is client or subscriber class.


using System;
// Main program
class Program
{
    static void Main(string[] args)
    {
        Button button = new Button();
        //subscribe click event with Client_ClickHandler
        button.click += Client_ClickHandler;
        // call a method of Button which will in turn raise event
        button.ClickEventRaiser();
    }
    private static void Client_ClickHandler(string message)
    {
        if (message != null)
        {
            Console.WriteLine("Button is clicked " + message);
        }
    }
}

Step1: The Program class creates an object of Button class to subscribe/consume event(s) of Button.

Step2: The button object uses dot operator followed by event click. It implies that click event of button object is going to be subscribed by Program class. But to subscribe this event the client class must tell the method which will handle the event data when it will be received by Program object. In RHS operand of += we specify the event handler method. This event handler will receive event data. Note that the event handler method must have compatible signature to accept all the data sent from publisher Button class. As there is only one data sent which is string type, so, we have a compatible event handler in Program class called Client_ClickHandler. This method takes one parameter of string type.

Step3: Subscribing event in Step2 is not enough. The subscriber class must call a method of Button class which will raise event. The method ClickEventRaiser in Button class is therefore called.

Step4: When event will be raised, the data will be sent from Button using delegate. That data/message will be received by event handler called Client_ClickHandler.

The above is the simple example to explain click event which is implemented using delegate instead of Event.

Another Delegate for Double Click event

What if Button class has another event called dblclick implemented using another delegate called DblClickDel. In the following code, we modify the publisher (Button) and subscriber(Program) classes to add another delegate for double click event.

public delegate void ClickDel(string message);
public delegate void DblClickDel(string message);
class Button
{
    public ClickDel click;
    public DblClickDel dblclick;
    public void ClickEventRaiser()
    {
        OnClick("Inside ClickEventRaiser");
    }

    private void OnClick(string str)
    {
        if (click != null)
        {
            click.Invoke(str);
        }
    }
    public void DoubleClickEventRaiser()
    {
        OnDblClick("Inside ClickEventRaiser");
    }

    private void OnDblClick(string str)
    {
        if (dblclick != null)
        {
            dblclick.Invoke(str);
        }
    }
}
Look at the client Program class code as given below. Read each comment carefully. The dblclick event is subscribed in way similar to click event. We have used separate event handler for dblclick event. In this example, we could have used the same event handler which is used for single click event (because both event handlers have similar method signature). Note that both delegates have same signature. If they had different signatures then event handler for both events must be different. 

using System;
// Main program
class Program
{
    static void Main(string[] args)
    {
        Button button = new Button();
        //subscribe click event with Client_ClickHandler
        button.click += Client_ClickHandler;
        // call a method of Button which will in turn raise event
        button.ClickEventRaiser();

        //subscribe dblclick event with Client_DblClickHandler
        button.dblclick += Client_DblClickHandler;
        // call a method of Button which will in turn raise event
        button.DoubleClickEventRaiser();
    }
    private static void Client_DblClickHandler(string message)
    {
        if (message != null)
        {
            Console.WriteLine("Button is double clicked " + message);
        }
    }

    private static void Client_ClickHandler(string message)
    {
        if (message != null)
        {
            Console.WriteLine("Button is clicked " + message);
        }
    }
}

Using Event Instead of Delegate

In above examples, we have used delegates for event programming. C# provides Event to facilitate the coding. Event provides better syntax compared to delegate and provides encapsulation. We modify the above examples for Event programming.


public delegate void ClickDel(string message);
class Button
{
    public event ClickDel click;
    public void ClickEventRaiser()
    {
        OnClick("Inside ClickEventRaiser");
    }
    private void OnClick(string str)
    {
        if (click != null)
        {
            click.Invoke(str);
        }
    }
}

Note that we have used event keyword to convert click delegate into click event. The client code is as follows. It is not modified.

using System;
// Main program
class Program
{
    static void Main(string[] args)
    {
        Button button = new Button();
        //subscribe click event with Client_ClickHandler
        button.click += Client_ClickHandler;
        // call a method of Button which will in turn raise event
        button.ClickEventRaiser();
    }
    private static void Client_ClickHandler(string message)
    {
        if (message != null)
        {
            Console.WriteLine("Button is clicked " + message);
        }
    }
}

We define an event using delegate. The event keyword is followed by delegate type and then an event variable is used to declare an event. The above code does not seem to be better in any way that when we used only delegate (not event). The real benefit of event is obvious when we use build-in delegate in event programming. In stead of custom delegates ( ClickDel or DblClickDel ), we use built-in delegate in the following modified code.

Button class code is as follows.


class Button
{
    public event EventHandler click; // EventHandler is built-in delegate
    public void ClickEventRaiser()
    {
        OnClick();
    }
    private void OnClick()
    {
        if (click != null)
        {
            click.Invoke(this, EventArgs.Empty);
        }
    }
}

Program class code is modified for event handler method because we have used EventHandler built-in method in Button class. The EventHandler delegate takes two parameters of types object and EventArgs. So, we use Client_ClickHandler with 2 parameters compatible with EventHandler.


using System;
// Main program
class Program
{
    static void Main(string[] args)
    {
        Button button = new Button();
        //subscribe click event with Client_ClickHandler
        button.click += Client_ClickHandler;
        // call a method of Button which will in turn raise event
        button.ClickEventRaiser();
    }
    private static void Client_ClickHandler(object Sender, EventArgs e)
    {
        Console.WriteLine( Sender.ToString()+ " is clicked " +   e.ToString());
    }
}
The following is old post.

Event, Publisher and Subscriber classes

Event is message which is sent from event sender class (i.e. publisher) to the event receiver (i.e. subscriber) class to signal the occurrence of an action. Here, action is the method in the sender class in which event is invoked. Event sender class is the publisher class that contains event definition and its invocation i.e. raising the event in a method.

Delegate Model

The event is defined using event keyword which is followed by a delegate and then the event name. Event is intimately related with delegate. The delegate before the event name implies what kind of method can be invoked when event occurs. In fact, event is a wrapper of delegate. Event is therefore said to be based on delegate model. The visibility of event is public. In the following code, EventHandler is an in-built delegate. EventHandler takes two parameters- sender object and event data. You can define an event using custom delegate as well but is rare in practice. EventHandler and its derived classes are enough to deal with events.

In the following code, an event named as ThresholdReached is defined in event class, Counter.


class Counter {
  public event EventHandler ThresholdReached;
  
  }


Raise Event using protected virtual method

Defining an event is not enough unless we define how the event is raised. Typically, to raise the event, we add a method that is marked as protected and virtual in the publisher class. Conventionally, the name of this method begins with On prefix followed by the event name e.g. OnThresholdReached. Look at the following code; the method OnThresholdReached is run then the ThresholdReached event is raised. Note that when event  ThresholdReached is raised then event sender object and event data (EventArgs) are passed as parameters. The event data object is an object of type EventArgs or its derived type.


class Counter
{
    public event EventHandler ThresholdReached; // define event

    protected virtual void OnThresholdReached(EventArgs e)
    {
        ThresholdReached?.Invoke(this, e); // raise the event
    }

    // provide remaining implementation for the class
}

Subscriber class

Raising event is received by another entity, called subscriber of the event. Events in .NET are based on the delegate model. The delegate model follows the observer design pattern, which enables a subscriber to register with and receive notifications from a provider. An event sender pushes a notification that an event has happened, and the subscriber i.e. the event receiving class receives that notification and defines a response to it. The response is defined using an event handler method.

Recall that an event is a message sent by an object to signal the occurrence of an action. For example, the action can be caused by user interaction, such as a button click, or it can result from some other program logic, such as changing a property's value. The object that raises the event is called the event sender or publisher. 

The event sender i.e. publisher doesn't know which object or method will receive (handle) the events it raises.

Delegates with events

Delegates have many uses in .NET. In the context of events, a delegate is an intermediary (or pointer-like mechanism) between the event source and the code that handles the event. You associate a delegate with an event by including the delegate type in the event declaration. In other words, event is wrapper of delegate. Note that the event is an intermediary between publisher and subscriber objects.

EventHandler

.NET provides the EventHandler and EventHandler delegates to support most event scenarios. Use the EventHandler delegate for all events that don't include event data. Use the EventHandler 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).

A delegate acts as an event dispatcher for the class that raises the event by maintaining a list of registered event handlers for the event.

What is event handler?

Event handler is a method in the subscriber class which receives the event. To respond to an event, you define an event handler method in the subscriber i.e. event receiving class. This event handler method must match the signature of the delegate for the event for which the handling code is written. In the event handler method, we perform the actions that are required when the event is raised, such as print a message after the user clicks a button. To receive notifications when the event occurs, event handler method must subscribe to the event.

Therefore, we create subscriber class in which we define the event handler method. We create an instance of the publisher class in this subscriber class. We attach the event raising method of the publisher class with this instance and then use += operator to bind it with the event handler method. Look at the following code.


class Subscriber
{
    static void Main()
    {
        var c = new Counter(); // instance of publisher
        c.ThresholdReached += SubscriberThresholdReached; // event handler delegate in right hand

        // provide remaining implementation for the class
    }
    // event handler method
    static void SubscriberThresholdReached(object sender, EventArgs e)
    {
        Console.WriteLine("The threshold was reached.");
    }
}

Static and dynamic event handlers

.NET allows subscribers to register for event notifications either statically or dynamically. Static event handlers are in effect for the entire life of the class whose events they handle. Dynamic event handlers are explicitly activated and deactivated during program execution, usually in response to some conditional program logic. For example, they can be used if event notifications are needed only under certain conditions or if an application provides multiple event handlers and run-time conditions define the appropriate one to use.

.NET provides the EventHandler and EventHandler<TEventArgs> delegates to support most event scenarios. Use the EventHandler delegate for all events that don't 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).

Steps in Event Programming

  1. Define a publisher class.
  2. Define event in the publisher class.
  3. Define an event raising method in publisher class.
  4. Raise the event in the a method in publisher class.
  5. Define a subscriber class.
  6. Create an object of the publisher class in it.
  7. Subscribe the publisher event with event handler method of subscriber using += operator. The += is used to register or subscribe the event with event handler given as RHS operand. The -= is used to unregister or unsubscribe event with event handler.
  8. Define the event handler method in the subscriber class.

Example 1- Event Raised and Subscribed  The following example shows how to raise and consume an event that doesn't have data. It contains a class named BusinessProcess that has an event called ProcessCompleted. This event is raised when OnProcessCompleted action is called in ProcessStart metod. Just after raising the event, the control goes to subscriber class called Program. This class invokes event handler method called Pb_ProcessCompleted. The method signature of this Pb_ProcessCompleted must match that of Notify delegate.


using System;
namespace ConsoleApp1
{
    public delegate void Notify(); // custom delegate defined
    class Program
    {
        static void Main(string[] args)
        {
            //ProcessCompleted event will be raised when ProcessStart runs.
            // as it contains the OnProcessCompleted event raiser method.
            // so the line of code with Pb_ProcessCompleted is executed after pb.ProcessStart
            BusinessProcess pb = new BusinessProcess();
            pb.ProcessCompleted += Pb_ProcessCompleted;
            pb.ProcessStart();

        }

        private static void Pb_ProcessCompleted()
        {
            Console.WriteLine( "Process is complete");
        }
    }
    class BusinessProcess // publisher class
    {
        public event Notify ProcessCompleted; // event defined
        public void ProcessStart()
        {
            Console.WriteLine("Process Started!");
            OnProcessCompleted(); // invoke the event raiser method
        }

        protected virtual void OnProcessCompleted()
        {
            Console.WriteLine( "Invoke the event");
            ProcessCompleted?.Invoke(); // event raised, will be handled by event handler method
        }
    }
}

Example 2- Event without event data The following example shows how to raise and consume an event that doesn't have event data. It contains a class named Counter that has an event called ThresholdReached. This event is raised when a counter value equals or exceeds a threshold value. The EventHandler delegate is associated with the event because no event data is provided. The event raising Add method of event sender class is called again and again. The Add method is defined so that it invokes the event named as ThresholdReached. Note as per convention, it should be named OnAdd but it is not mandatory.


using System;

namespace ConsoleApplication1
{
    class ProgramOne
    {
        static void Main(string[] args)
        {
            Counter c = new Counter(new Random().Next(10));
            c.ThresholdReached += c_ThresholdReached;

            Console.WriteLine("press 'a' key to increase total");
            while (Console.ReadKey(true).KeyChar == 'a')
            {
                Console.WriteLine("adding one");
                c.Add(1);
            }
        }

        static void c_ThresholdReached(object sender, EventArgs e)
        {
            Console.WriteLine("The threshold was reached.");
            Environment.Exit(0);
        }
    }

    class Counter
    {
        private int threshold;
        private int total;

        public Counter(int passedThreshold)
        {
            threshold = passedThreshold;
        }

        public void Add(int x)
        {
            total += x;
            if (total >= threshold)
            {
                ThresholdReached?.Invoke(this, EventArgs.Empty);
            }
        }

        public event EventHandler ThresholdReached;
    }
} 

Examples 3.1,3.2 and 3.3 are based on following facts.

  • User inputs two integer numbers.
  • If the sum of these two numbers is greater than 100 then raise an event.
  • The user will be notified that the sum is greater than 100.
  • In example 3.3, event returns sum data to the event handler method.

Example 3.1- Event without event data using custom delegate


using System;
namespace ConsoleApp1
{
    class Program // subscriber class
    {
        static void Main(string[] args)
        {
            Publisher publisher= new Publisher();
            publisher.notify += Publisher_notify; // delegate match
            publisher.Add(10,99);
        }

        private static void Publisher_notify() // event handler method
        {
            Console.WriteLine("Sum is greater than 100.");
        }
    }
    public delegate void Notify();
    class Publisher
    {
        public event Notify notify;

        public void Add(int num1, int num2) 
        {
            int sum = num1 + num2;
            if (sum > 100)
            {
                notify.Invoke(); // raise the event
            }
        }
    }
}

Example 3.2- Event without event data using in-build delegate EventHandler

The EventHandler takes two parameters, sender object and EventArgs type event data. This is why we use two arguments with Invoke method. In the subscriber, the event handler method must have the same types of parameters.

using System;
namespace ConsoleApp1
{
    class Program// subscriber class
    {
        static void Main(string[] args)
        {
            Publisher publisher = new Publisher();
            publisher.notify += Publisher_notify; // delegate match
            publisher.Add(10, 99);
        }

        private static void Publisher_notify(object sender, EventArgs e)
        {
            Console.WriteLine("Sum is greater than 100.");
        }
    }
    class Publisher
    {
        public event EventHandler notify;

        public void Add(int num1, int num2)
        {
            int sum = num1 + num2;
            if (sum > 100)
            {
                notify.Invoke(this, EventArgs.Empty); // raise the event
            }
        }
    }
}

Example 3.3- Event with event data using in-build delegate EventHandler

In this example, integer type data is sent by the publisher to the subscriber. The event handler consumes that data.

using System;
namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Publisher publisher = new Publisher();
            publisher.notify += Publisher_notify;
            publisher.Add(10, 99);
        }

        private static void Publisher_notify(object sender, int e)
        {
            Console.WriteLine("Sum "+ e.ToString() +" is greater than 100.");
        }
    }
    class Publisher
    {
        public event EventHandler<int> notify;

        public void Add(int num1, int num2)
        {
            int sum = num1 + num2;
            if (sum > 100)
            {
                notify.Invoke(this, sum);
            }
        }
    }
}

Summary

  • The class who raises events is called Publisher, and the class which receives the notification is called Subscriber
  • Typically, a publisher raises an event when some action occurred.
  • There can be multiple subscribers of a single event.
  • Event is an encapsulated delegate i.e. a wrapper around a delegate. It depends on the delegate.
  • The delegate defines the signature for the event handler method of the subscriber class. The signature of the handler method must match the delegate signature.
  • Events in .NET follow the observer design pattern.
  • Use "event" keyword with delegate type variable to declare an event.
  • Register with an event using the += operator. Unsubscribe it using the -= operator.
  • Pass event data using EventHandler<TEventArgs>.
  • Derive EventArgs base class to create custom event data class.
  • Event is better than delegate in the sense of encapsulation and succinct syntax. 

Sunday, July 9, 2023

C# Nullable String Explained


Look at the following code.
public class Book
{
    public string BookName { get; set; } = "";
}

There is problem with the above code; although it hides the compiler warning. In the above code, if we remove the initialization of BookName, the C# compiler will warn you as shown below. 

A developer can overlook this warning or can remove the warning by initializing the BookName by ZLS i.e. zero length string as done in the above code. But this will give wrong business notion. It will mean that we are initializing the BookName with a name that is not existing in the real world. Who will name the book name as ZLS? Surely, no one. So, assigning ZLS to BookName is bad idea.

Think well. Maybe we have not still decided about the name of the book and will give it name in future. In this case, null value is expected because a null means unknown value. When the book name is not still given, it is unknown. The string? BookName implies that the BookName is not still initialized and will be initialized later somewhere in the code. Right now it is unknown. This is the good idea. To meet this idea, we use nullable string. The code will be as follows.


public class Book
{
    public string? BookName { get; set; }
}

The reference type string variable BookName is changed into nullable reference type. So, another alternative may be to change such members to nullable reference types.

Another alternative to remove the warning is by using parameterized constructor as given below.


 public class Book
    {
        public Book(string name)
        {
            BookName = name;
        }
        public string BookName { get; set; }
    }

In this case, default constructor is removed. In case of default constructor, the string type BookName will get its default value which is null. You can use the null forgiving operator or parameterized constructor to indicate that a member is initialized in other code.

The string datatype variable is non-nullable and so it must contain a nun-null value. If still you have doubt, look at the warning.


Read the documentation. CS8618 - Non-nullable variable must contain a non-null value when exiting constructor. Consider declaring it as nullable.

Non-nullable data means that the variables should get a "useful" initialization by the time we use them. Is int type variable initialized with zero a useful initialization in business scenario? Discuss. Other blog on this topics.


Thursday, July 6, 2023

C# Encoding and Decoding UTF

Unicode Transformation

UTF stands for Unicode Transformation Format. There are many types of Unicode transformation format (also called Unicode encoding styles) such as UTF-7, UTF-8, UTF-16, UTF-32 etc. Here 7, 8, 16 and 32 refer to the number of bits used to encode or convert a character of the character set mapped to code point into the format code. 

First of all, given a character of the character set, it is mapped to a number (called code point). This number is encoded into sequence of bits (depending upon the number of bits used to do the transformation, encoding format is decided). Encoding means converting a character code point into sequence of bits of 0 and 1. Decoding is inverse of encoding. Decoding means getting back the code point from sequence of bits of 0 and 1.
Therefore,
  • Each character is mapped to a number, called code point.
  • The code point is encoded into sequence of bits; the number of bits used depends upon the transformation format.
  • Encoding means converting a character into sequence of bits.
  • Decoding means converting a sequence of bits into a character.

Character set in HTML

In HTML documents, the character set used in the document is described using charset attribute of the meta tag. For example in HTML5, <meta charset="UTF-8"> implies that the UTF-8 is used in the document.


using System;

namespace EncodingDecoding
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("First Approach: Char.ConvertToUtf32 & Char.ConvertFromUtf32");
            string alphabets = "The quick brown fox jumps over the lazy dog";
            for (int i = 0; i < alphabets.Length; i++)
            {
                Int32 x = Char.ConvertToUtf32(alphabets, i);
                Console.Write(x);
                Console.Write(" integer represents ");
                Console.Write(Char.ConvertFromUtf32(x));
                Console.WriteLine();
            }
            Console.WriteLine("\nSecond Approach : Typecast");
            string quote = "He who has a why to live can bear almost any how.";
            char[] chars = quote.ToCharArray();
            foreach (var c in chars)
            {
                Console.WriteLine(c+" "+ (int)c);
            }
            Console.ReadKey();
        }       
    }
}

OUTPUT:
First Approach: Char.ConvertToUtf32 & Char.ConvertFromUtf32
84 integer represents T
104 integer represents h
101 integer represents e
32 integer represents
113 integer represents q
---

Second Approach : Typecast
H 72
e 101
  32
w 119
h 104
---

C# Example to convert a character into string


using System;
using System.Reflection;

class Example
{
    static void Main()
    {
        Type t = typeof(String);

        MethodInfo substr = t.GetMethod("Substring",
            new Type[] { typeof(int), typeof(int) });

        Object result =
            substr.Invoke("Hello, World!", new Object[] { 7, 5 });
        Console.WriteLine("{0} returned \"{1}\".", substr, result);
        Console.ReadKey();
    }
}
C# Char


using System;
namespace ConsoleToString
{
    class Program
    {
        static void Main(string[] args)
        {
            char ch = 'A';
            Console.WriteLine(ch.ToString());       // Non-static method Output: "A"
            Console.WriteLine(Char.ToString('B'));  // static Method Output: "B"
            Console.ReadKey();
        }
    }
}


Monday, March 14, 2022

C# Count each letter in a sentence

Create a console application.


using System;
using System.Collections.Generic;
namespace CountLetters
{
    class Program
    {
        static void Main(string[] args)
        {
            string name = "AABBCCDEFAJEET";
            char[] letters = name.ToCharArray();
            
            Dictionary dic = new Dictionary();
            for (int i = 0; i < letters.Length; i++)
            {
                int count = Array.FindAll(letters, x => x == letters[i]).Length;
                if (!dic.ContainsKey(letters[i]))
                {
                    dic.Add(letters[i], count);
                }
            }
            foreach (var item in dic)
            {
                Console.WriteLine("{0} {1}", item.Key, item.Value);
            }
            Console.ReadKey();
        }
    }
}
OUTPUT
A 3
B 2
C 2
D 1
E 3
F 1
J 1
T 1

Wednesday, March 9, 2022

C# Factorial of big integer number

Create a console application.


using System;
using System.Numerics;

namespace BigIntegerConsoleApp
{
    class Program
    {
        public static BigInteger factorial(BigInteger n)
        { 
            if (n==1 || n==0)
            {
                return 1;
            }
            return n * factorial(n - 1);
        }

        static void Main(string[] args)
        {
            BigInteger result = factorial(999);
            Console.WriteLine(result.ToString());
            Console.ReadLine();
        }
    }
}

Monday, November 1, 2021

C# Collections Part1 Array Vs ArrayList




Collections are an important concept in C# programming. There are many important collection classes in the System.Collections namespace such as ArrayList, Hashtable, SortedList, Stack, Queue etc. These classes are used as different types of data structures. These different types of classes have been developed in .NET keeping in mind the different requirements.

The general meaning of a collection is a collection of objects. These different  items within the collection can be similar or dissimilar. Array is a collection of similar types of elements while ArrayList is a collection of dissimilar types of elements.

Array is a collection in .NET's System namespace, in which all elements are of same datatype. So Array is a type safe data structure but one of its limitations is that it can store only a predetermined number of elements. This means that once the size of the array is initially determined, its size cannot be increased or decreased.

Although its size can be changed using the Resize method with Array, but by doing this, a new Array object is created which copies the data of the old Array into this new Array.

The example of Array is explained in the following code.

using System;
namespace ArrayClass
{
    class Program
    {
        static void Main(string[] args)
        {
            // array is created using new keyword
            // array size must be given or array must be initialized 
            int[] arrInt = new int[4];
            Console.WriteLine("Array size is {0}", arrInt.Length);
            //auto initialized
            Console.WriteLine("\n-----------------------");
            Console.WriteLine("Auto initialized value at 0 index is {0}", arrInt[0]);
            Console.WriteLine("Auto initialized value at 1 index is {0}", arrInt[1]);
            Console.WriteLine("Auto initialized value at 2 index is {0}", arrInt[2]);
            Console.WriteLine("Auto initialized value at 3 index is {0}", arrInt[3]);
            //re-initialize
            arrInt[0] = 11;
            arrInt[1] = 21;
            arrInt[2] = 13;
            arrInt[3] = 14;
            Console.WriteLine("\n-----------------------");
            Console.WriteLine("Reinitialized value at 0 index is {0}", arrInt[0]);
            Console.WriteLine("Reinitialized value at 1 index is {0}", arrInt[1]);
            Console.WriteLine("Reinitialized value at 2 index is {0}", arrInt[2]);
            Console.WriteLine("Reinitialized value at 3 index is {0}", arrInt[3]);
            //resize array using Array.Resize() method
            Array.Resize(ref arrInt, 6);
            Console.WriteLine("\n-----------------------");
            Console.WriteLine("After resize, value at 0 index is {0}", arrInt[0]);
            Console.WriteLine("After resize, value at 1 index is {0}", arrInt[1]);
            Console.WriteLine("After resize, value at 2 index is {0}", arrInt[2]);
            Console.WriteLine("After resize, value at 3 index is {0}", arrInt[3]);
            Console.WriteLine("After resize, value at 0 index is {0}", arrInt[4]);
            Console.WriteLine("After resize, value at 1 index is {0}", arrInt[5]);
            Console.WriteLine("\n-----------------------");
            //sort array using Array.Sort() method
            Array.Sort(arrInt);
            for (int i = 0; i < arrInt.Length; i++)
            {
                Console.WriteLine("After sorting, value at {0} index is {1}" , i, arrInt[i]);
            }
            Console.WriteLine("\n-----------------------");
            // array size not given but array initialized 
            string[] cities = new string[] { "Delhi", "Agra", "Patna", "Bhopal"};
            foreach (string city in cities)
            {
                Console.WriteLine(city);
            }
            Console.WriteLine("\n-----------------------");
            // array size not given but array initialized without new keyword 
            string[] continents = { "Asia", "Europe", "Africa", "Australia" };
            foreach (string continent in continents)
            {
                Console.WriteLine(continent);
            }
            Console.WriteLine("\n-----------------------");
            //copy array into another array
            string[] continents2 = new string[5];
            Array.Copy(continents, continents2, continents.Length);
            continents2[4] = "America";
            foreach (var cont in continents2)
            {
                Console.WriteLine(cont);
            }
            // convert array datatype using Array.ConvertAll method
            float[] numbers = new float[5];
            numbers[0] = 1.43f;
            numbers[1] = 2.75f;
            numbers[2] = 4.70f;
            numbers[3] = 8.80f;
            numbers[4] = 7.50f;
            double[] dblNumbers = Array.ConvertAll(numbers, new Converter( n=>Convert.ToDouble(n)));
            Console.WriteLine("\n-----------------------");
            Console.WriteLine("Float to Double conversion:\n");
            for (int i = 0; i < dblNumbers.Length; i++)
            {
                Console.WriteLine(numbers[i] +" => "+ dblNumbers[i]);
            }
            Console.ReadKey();
        }
    }
}
Cinema hall vs Website
Therefore, while Array provides type safety on one hand, on the other hand it does not give the flexibility to change the size. If the requirement of the business is such that the size of the data does not have to be changed, then you can use Array. For example the number of seats in a cinema hall. After the construction of the cinema hall, number of seats in the audience hall is fixed. Use of Array is desirable for such case. In contrast, the number of user members of a website cannot be fixed. Initially the number of members may be 30-40 but with time its number may increase immensely. So Array is not desirable in such situation.

ArrayList as Collection or Data Structure
Keeping in mind the limitation of Array, a class named ArrayList has been created inside the System.Collections namespace. The merit of this .NET ready-made class is that in this case, the number of elements in the ArrayList class can be increased or decreased according to the requirement.

While Array is typesafe, ArrayList is not typesafe. All the elements in Array have the same data type but elements of ArrayList can be of different datatypes.

using System;
using System.Collections;

namespace ProjectArrayList
{
    class Program
    {
        static void Main(string[] args)
        {
            ArrayList Employee = new ArrayList();
            //ArrayList accepts all types of data because it adds Object type data
            Employee.Add("Amit");
            Employee.Add(30);
            Employee.Add("HR");
            Employee.Add(40000);
            //list ArrayList Employee data
            foreach (var data in Employee)
            {
                Console.WriteLine(data);
            }
            //Object Initializer to add items in one step
            Console.WriteLine();
            ArrayList Product = new ArrayList() { "Mobile", 200000, "Black", "Samsung", "J7-Prime" };
            //accessing ArrayList object using index
            for (int i = 0; i < Product.Count; i++)
            {
                Console.WriteLine(Product[i]);
            }
            //There are several methods of ArrayList to add items, to remove items in several ways
            //Create an ArrayList object called Student
            Console.WriteLine();
            ArrayList Student = new ArrayList() { 1, "Anand", "MCA", "Semester5", true, 20000 };
            //add item at the end of the Student items
            Student.Add("Agra");
            //insert at a specified index postion
            Student.Insert(2, "Gupta");
            foreach (var item in Student)
            {
                Console.WriteLine(item);

            }
            Console.WriteLine();
            //remove an item
            Student.Remove("Semester5");
            //remove an item at index position
            Student.RemoveAt(2);
            foreach (var item in Student)
            {
                Console.WriteLine(item);

            }
            Console.WriteLine("Total items in Student ArrayList object: {0}", Student.Count);
            Console.WriteLine("Total Capacity of Student ArrayList object: {0}", Student.Capacity);
            Console.WriteLine("BCA item exists or not: {0}",Student.Contains("BCA"));
            Console.ReadKey();
        }
    }
}
Index vs Key
In the above example, we have seen some important properties and methods of ArrayList. Like Array, the elements of ArrayList are selected on the basis of index. This can sometimes cause problems. Suppose the number of members under the ArrayList is very high, then in such a situation, to access a particular member, its index number will have to be seen. Sometimes it may happen that its index number will be wrongly entered by the programmer and in such case programming error will occur in the code. This problem is also with Array because Arrays are also based on index. To avoid this situation, it is desirable to use key instead of index. The key is used to access a member within a Hashtable collection. Hashtable is in the System.Collections namnamespace like ArrayList.

using System;
using System.Collections;

namespace ProjectHashtable
{
    class Program
    {
        static void Main(string[] args)
        {
            Hashtable Laptop = new Hashtable();
            Laptop.Add("Acer", "20000,Black");
            Laptop.Add("HP", "30000,White");
            Laptop.Add("Asus", "45000,Silver");
            Laptop.Add("Apple", "60000,Gold");
            
            foreach (var value in Laptop.Values)
            {
                Console.WriteLine(value);
            }

            foreach (var key in Laptop.Keys)
            {
                Console.WriteLine(key);
            }
            Console.WriteLine(Laptop.ContainsKey("acer"));
            Console.WriteLine(Laptop.ContainsKey("Acer"));
            Console.WriteLine(Laptop.ContainsValue("60000"));
            Console.WriteLine(Laptop.ContainsValue("60000,Gold"));
            Console.WriteLine("Count Items in Laptop: {0}",Laptop.Count);
            //does not throw exception if key is not found
            Laptop.Remove("HP");
            Laptop.Clear();
            Console.WriteLine("Count Items in Laptop: {0}",Laptop.Count);
            Console.ReadLine();
        }
    }
}

Edited on 5th July 2023

C# Abstract Class and Abstract Method



Abstract method

Method of a class is used to define the behavior of the class. Abstract method is a method that has no implementation of its behavior. In other words, the abstract method does not have body. In the body of a method, its behavior is defined. As abstract method is without body, it misses its behavior. Implementing a method means defining the behavior of the method. An abstract method has only method signature and 'abstract' modifier is used with it. for example
public abstract double Add(double number1, double number2);
public abstract double Subtract(double number1, double number2);
public abstract double Multiply(double number1, double number2);
public abstract double Divide(double number1, double number2); 

Abstract class

Abstract class and abstract method are related to each other. As we know that in object-oriented programming, method is a member of class; if a method in the class is abstract method then the class must be an abstract class. In other words, class containing an abstract member will be abstract class. It is very logical because the presence of abstract method implies that some behavior of the class is still missing and not defined. Obviously, such class must be abstract.

But an abstract class can be without any abstract member as well. In this case, we recognize the abstract class with the abstract modifier used with the class.
public abstract class AbsClass
{
// It's an abstract class
}
Example of abstract class with an abstract method:
public abstract class AbsClass
{
   public abstract void Display();
   public void Message()
   {
    Console.WriteLine("Non-abstract method");
  }
}
The most important point is that an instance of an abstract class cannot be created. For example the following statement is wrong.
AbsClass obj = new AbsClass();
There can be both abstract and non-abstract methods within an abstract class. For example the following abstract class has both abstract and non abstract methods.

public abstract class AbsClass
{
public abstract void Display();
public void Message()
{
Console.WriteLine("Non-abstract method");
}
}
Unless all the methods of the abstract class are implemented, the abstract class cannot be consumed except for static methods. For example, the abstract method Display of the above AbsClass class is implemented in the following code in the Child class, which inherits AbsClass.
public abstract class Child : AbsClass
{
public abstract void Display()
{
Console.WriteLine("Display method is implemented.");
}
}
To consume an abstract class, its child class must implement all the abstract methods of the abstract class. If a child class has a single method abstract, then that child class will be become abstract and hence cannot be instantiated.

Consume non-abstract static method of Abstract class

Following example shows that a public static non-abstract method of an abstract class can be consumed in another class.
using System;
using System.Collections.Generic;

namespace ConsoleAppArray
{
    abstract class AbstractClass
    {
        public static void Show()
        {
            Console.WriteLine("I am in a static method of abstract class");
        }
    }
    public class Program
    {
        static void Main(string[] args)
        {
            AbstractClass.Show();
        }
    }
}

.NET Abstract Class Examples

Assembly class is an abstract class. It represents an assembly, which is a reusable, versionable, and self-describing building block of a common language runtime application.

public abstract class Assembly : System.Reflection.ICustomAttributeProvider, System.Runtime.Serialization.ISerializable
Example of using methods of Assembly class


using System;
using System.Reflection;

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            string location = Assembly.GetAssembly(typeof(Program)).Location;
            Console.WriteLine(location);
            location = Assembly.GetEntryAssembly().Location;
            Console.WriteLine(location);
            location = Assembly.GetExecutingAssembly().Location;
            Console.WriteLine(location);
        }
    }
}


Edited on 5th July 2023

C# String vs StringBuilder



String and StringBuilder are two important classes in C sharp programming which are used for manipulation of strings. It is very important for a programmer to understand the difference between these two, as strings are used extensively in programs and string manipulation within the programs is very common.
  • String class belongs to System namespace.
  • StringBuilder belongs to System.Text namespace.
The String class should be used in situations when the value of the string within the program is usually constant, immutable, meaning that it does not require much manipulation. On the contrary, the StringBuilder class should be used when the string is to be manipulated repeatedly in the program. 

The reason behind this is that when the concatenation of a string occurs with another string, a new string object is created within the heap. If this process is repeated again and again, many string objects will be created within the heap. Thus a lot of memory will be used up to allocate memory within the heap. In other words, the memory usage will slow down the speed of the program and will adversely affect the performance of the program. StringBuilder class should be used if you have to do string manipulation repeatedly in your program. The property of StringBuilder class is that when string concatenation is performed again and again, new objects of StringBuilder are not created in the heap. On the contrary, the capacity of the StringBuilder object increases, only its memory allocation changes.

An object of the StringBuilder class has an initial capacity of its own. Initially this capacity is of 16 characters i.e. 2 bytes. In other words, initially the StringBuilder object holds 16 characters in its memory, but if the size of the string exceeds 16 characters, the capacity of the StringBuilder object is doubled. That is to say, it increases from 16 characters to 32 characters i.e. 4 bytes. As the size of the string increases, the capacity of the StringBuilder object also increases, but only one and the same object of the StringBuilder remains in the heap.

On comparing StringBuilder and String class, it is found that the performance of StringBuilder class is better than that of String class. We can also understand this fact with the help of the following example.

using System;
using System.Diagnostics;
using System.Text;

namespace StringVsStringBuilder
{
    class Program
    {
        static void Main(string[] args)
        {
            string str1 = "";
            string str2 = "";
            Stopwatch sw1 = new Stopwatch();
            sw1.Start();
            for (int i = 0; i < 100000; i++)
            {
                str1 = str1 + i;
            }
            sw1.Stop();
            Console.WriteLine("\nElapsed watch for String : {0}", sw1.ElapsedMilliseconds);
            Stopwatch sw2 = new Stopwatch();
            sw2.Start();
            StringBuilder sb = new StringBuilder(str2);
            for (int j = 0; j < 100000; j++)
            {
            sb.Append(j);
            }
            sw2.Stop();
            Console.WriteLine("Elapsed watch for StringBuilder: {0}", sw2.ElapsedMilliseconds);
            Console.ReadLine();
        }
    }
}

C# Interface



What is an interface? Interface literally means a medium for working between two things, such as a user interface. When we say user interface, it is the interface between the user and the system, allowing user to interact with the system.

In Object Oriented Programming (OOP), interface is a kind of contract between Interface type and the Class type. Interface is a type like class but interface contains only methods and properties. Unlike class, interface does not have any field. The methods in the interface are always public and abstract. Interface represents abstract behaviors which are implemented by the contracting class. The contracting class is the class that implements the interface.

In C#, we know that although a class can inherit another class, a class cannot inherit more than one class. In other words, C# does not support multiple inheritance. But C# allows to inherit multiple interfaces by a single class instead of inheritance of multiple classes. 
Although a class can inherit only one other class, but a class can inherit one or more interfaces. 
A class can inherit another class and multiple interfaces at the same time.

Class vs Interface
  • A class can have field but an interface cannot have field.
  • A class can have abstract , non abstract or any other kind of methods but interface has all its methods abstract and public methods.
  • Interface provides contract and class implements that contract.
  • Interface methods are abstract but 'abstract' modifier are not used with them but a class with abstract method must have abstract modifier with the method and the class.
  • Instance of a non abstract class can be created but instance of interface can never be created. (Because the methods of interface are always abstract.) 
  • A class can inherit an interface but not vice versa.
  • When a class inherits an interface, it cannot consume the interface directly. The class must, first of all, implement all the methods of the interface, only then the class can consume the methods of the interface. 
  • But when a class inherits another class, it is not necessarily required to implement the methods of the parent class. If the parent class has virtual methods, they can or cannot be overridden by the child class.  The virtual implies that the method is override-able in the child class. The child class can consume the parent class's methods directly and override them if needed. A parent class method without virtual modifier cannot be overridden by the child class.
So, when a class inherits another class it can consume the methods of its parent class directly or by overriding the methods, in other words, it can be re-implemented but in case of interface whenever a class inherits an interface, it must always implement the methods of the interface because the methods within the interface are abstract. They do not have any implementation within the interface, so whenever the class inherits the interface, it must implement the methods of that interface. Implementation of the method of interface by the inheriting class is mandatory. For example, to consume the InterfaceEx interface, the AddClass class implements all the methods of the InterfaceEx interface. Inheriting class cannot consume the interface methods unless and until all methods of the interface are implemented by the consuming class.

namespace InterfaceEx
{
    interface MyInterface
    {
        int Calculate(int num1, int num2);
        void DisplayResult(int result);
    }
}

using System;

namespace InterfaceEx
{
    class AddClass : MyInterface
    {
        public int Calculate(int num1, int num2)
        {
            return num1 + num2;
        }

        public void DisplayResult(int result)
        {
            Console.WriteLine("Sum of two integers: {0}", result.ToString());
        }
    }
}
The Program class is a client class that eventually consumes the AddClass class.

using System;

namespace InterfaceEx
{
    class Program
    {
        static void Main(string[] args)
        {
            AddClass c1 = new AddClass();
            c1.DisplayResult(c1.Calculate(20, 40));
            Console.ReadLine();
        }
    }
}
Some Facts about Interface
  • When a class inherits an interface, it must implement all the methods of the interface, it cannot consume the interface without implementing its all methods.
  • All the methods of interface are public and abstract but the explicit use of public and abstract keywords during method declaration is prohibited with the methods of interface.
  • There is no field in an interface.
  • Only public or internal access modifiers can be used with a class. Similarly, public or internal access modifiers can be used with interfaces.
  • One interface can inherit another interface. It means that methods of parent Interface will be inherited by the child Interface. Two interfaces can have methods of the same name with the same method signature. When a class implements both these interfaces then it has to adopt the methods.

C# Generic Delegates Func, Action and Predicate Delegates Examples


A delegate is used as a method pointer in C# program. Programmers can create their own delegates according to their need, but there are three types of built-in delegates which can be be used by programmers to save their time. These three types of delegates are as follows-
  • Func Delegate
  • Action Action Delegate
  • Predicate Delegate
Func Delegate points to a method which has a return type.
The Action delegate points to a method which does not have a return type.
The Predicate delegate points to a method which has a Boolean return type.

Function is a method that returns a value, on the contrary, subroutine or action is a method which does not return anything. In other words, a function that does not return a value is called action. So, The Action delegate points to the subroutine or method containing the action. Predicate delegate is actually a special type of Func delegate in which the return type of the method is Boolean.

Let us now understand the concept of delegate with the help of an example.

First let's create a method Add which returns double type data and then call it by using the Func delegate.

        public double Add(double number1, double number2)
        {
            return number1 + number2;
        }

Now we create a method Product which returns void and then call it by using the the Action delegate.

        public void Product(double number1, double number2)
        {
            double product = number1 * number2;
            Console.WriteLine("Action Delegate: Product is " + product.ToString());
        }
Now we create a method Status which returns Boolean type data and then call it by using the Predicate delegate.

        public bool Status(int age)
        {
            if (age >= 18)
                return true;
            return false;
        }

Depending on the return type of the methods, we call the methods with the help of different types of delegate.


using System;

namespace BuiltInDelegates
{
    class Program
    {
        public double Add(double number1, double number2)
        {
            return number1 + number2;
        }
        public void Product(double number1, double number2)
        {
            double product = number1 * number2;
            Console.WriteLine("Action Delegate: Product is " + product.ToString()); 
        }
        public bool Status(int age)
        {
            if (age >= 18)
                return true;
            return false;
        }
        static void Main(string[] args)
        {
            Program obj = new Program();
            Func AddDelegateObj = obj.Add;
            double result = AddDelegateObj.Invoke(22.5, 44.6);
            Console.WriteLine("Func Delegate: Sum is "+result.ToString());
            Action ProductDel = obj.Product;
            ProductDel(2, 4);
            Predicate PredicateDel = obj.Status;
            if (PredicateDel(17))
            {
                Console.WriteLine("You are eligible to vote.");
            }
            else
            {
                Console.WriteLine("You are not eligible to vote.");
            }

            Console.ReadKey();
        }
    }
}

Func<double, double, double> In this, the first two data types indicate the data type of the input parameters of the called method while the last parameter indicates the return type of the called method.

Action<double, double> In this, both data types indicate the input parameters of the called method because the action delegate refers to a method that does not return anything.

Predicate<int> Indicates that the called method has only one input parameter and that the return type of that method is Boolean data type

In the case of func only, the last parameter indicates the return type of the method, while in both the cases, the parameters indicate only the input parameters of the called method.


The above mentioned three methods can also be converted as anonymous methods and then call them with the help of generic delegate like Function, Action or Predicate. It is presented by the following example.

using System;

namespace BuiltInDelegates
{
    class Program
    {
        
        static void Main(string[] args)
        {
            Program obj = new Program();
            Func AddDelegateObj = delegate (double number1, double number2)
            {
                return number1 + number2;
            };
            double result = AddDelegateObj.Invoke(22.5, 44.6);
            Console.WriteLine("Func Delegate: Sum is "+result.ToString());
            Action ProductDel = delegate (double number1, double number2)
            {
                double product = number1 * number2;
                Console.WriteLine("Action Delegate: Product is " + product.ToString());
            };
            ProductDel(2, 4);
            Predicate PredicateDel = delegate (int age)
            {
                if (age >= 18)
                    return true;
                return false;
            };
            if (PredicateDel(17))
            {
                Console.WriteLine("You are eligible to vote.");
            }
            else
            {
                Console.WriteLine("You are not eligible to vote.");
            }

            Console.ReadKey();
        }
    }
}
LAMBDA EXPRESSION


using System;

namespace BuiltInDelegates
{
    class Program
    {
        
        static void Main(string[] args)
        {
            Program obj = new Program();
            Func AddDelegateObj =  (double number1, double number2) =>
            {
                return number1 + number2;
            };
            double result = AddDelegateObj.Invoke(22.5, 44.6);
            Console.WriteLine("Func Delegate: Sum is "+result.ToString());
            Action ProductDel =  (double number1, double number2) =>
            {
                double product = number1 * number2;
                Console.WriteLine("Action Delegate: Product is " + product.ToString());
            };
            ProductDel(2, 4);
            Predicate PredicateDel = (int age) =>
        {
                if (age >= 18)
                    return true;
                return false;
            };
            if (PredicateDel(17))
            {
                Console.WriteLine("You are eligible to vote.");
            }
            else
            {
                Console.WriteLine("You are not eligible to vote.");
            }

            Console.ReadKey();
        }
    }
}

C# Polymorphism Method overloading and Method Overriding


Polymorphism is an important concept in Object Oriented Programming. Polymorphism means one thing with potentially many forms. In programming, for example, if a same name method behaves differently in different situations, then method is called to be polymorphic. Method overloading and Method overriding are examples of method polymorphism. Method overloading is called Compile time polymorphism. Method overriding is called Runtime polymorphism.

If a method has the same name, then there must be some difference in it due to which there is a difference in its behavior. One of the reasons for the variation in the behavior of the method must be the variation in the type of parameters of the method. The parameter of a method is exactly the same as the input to a system. Just as the system gives a fixed output when input is entered into a system, similarly a method can be given zero or more inputs. The input to the method is called parameter. 
Parameter Matter for Method Overloading
More number of parameters passed to method, the greater the load on the method because the method has to do some processing work for each parameter. That's why method overloading refers to the nature of parameters passed to the method which the method processes and returns a certain output. Method overloading refers not only to the number of parameters passed over the method but also to the nature of the parameter i.e. the data type of the parameter and the order of the parameters. The order in which the parameters are being entered within the method affects the method's output. Therefore, the variation in the type of the parameter of the method means the following type of variation.
  1. Number of parameters
  2. datatype of parameter
  3. Order of Parameters
We will understand these three types of Method Overloading with examples. A method named Method has been created in the following program class, which is overloaded with different parameters passed to the Method method. 
  • The first method is without any parameter.
  • The second method  has one parameter. of int datatype.
  • The third method  has one parameter. of string datatype.
  • The fourth method  has two parameters, int type parameter followed by string type parameter. 
  • The fifth method  has two parameters, string type parameter followed by int type parameter. 
Thus, even though they have same name, these methods behave differently due to parameters. This is an example of method overloading.

using System;

namespace MethodOverloads
{
    class Program
    {
        void Method()
        {
            Console.WriteLine("Method 1: No parameter"); 
        }
        void Method(int i)
        {
            Console.WriteLine($"Method 2: One Parameter of int type {i}");
        }
        void Method(string s)
        {
            Console.WriteLine($"Method 3: One Parameter of string type: {s}");
        }
        void Method(int i, string s)
        {
            Console.WriteLine($"Method 4: Two Parameters; int type parameter followed by string type parameter: {i}, {s}");
        }
        void Method(string s, int i)
        {
            Console.WriteLine($"Method 5: Two Parameters; string type parameter followed by int type parameter: {s}, {i}");

        }

        static void Main(string[] args)
        {
            Console.WriteLine("Examples of method overloading:-");
            Program p = new Program();
            p.Method();
            p.Method(100);
            p.Method("Ajeet");
            p.Method(200,"Amit");
            p.Method("Amit",300);
            Console.ReadLine();
        }
    }
}


Difference Between Method Overloading and Method Overriding
  • Method overloading requires some kind of change in the parameter of the method, whether it is the number of parameters or the data type of the parameter or there is a difference in the order of the parameters, in these three ways method overloading of a method is possible but Method Overriding does not change the parameter of method. Method Overriding occurs due to change in the body of the method. In other words method overriding is due to change in the processing logic in the body of the method. 
  • Method Overriding happens in derived class but Method overloading is possible in parent class or derived class.
  • Method overriding requires permission from the parent class, for this the virtual keyword is required along with methods within the parent class. If a virtual modifier is not used with a method of the parent class, that method cannot be overridden in the child. In contrast, method overloading in derived class does not require the permission of the parent class.
  • Method overriding is always done within the inherited class. In this way method overriding is a part of inheritance whereas method overloading is not a part of inheritance. Method overloading can be done within the class or its child class.
  • When the virtual keyword is used with a method within a parent class, that method can be overridden, but it is not necessary that the virtual method must be overridden. The virtual flag simply indicates that overriding of this method is possible within the child class.
  • If a method is to be overridden in derived class, it is mandatory to use the virtual keyword with that method in the super class. Method overloading does not require the virtual keyword.
  • The use of the override keyword override with a method indicates that a change has been made to the body of the method, that is, a method in a child class has changed from a method in its preceding parent class.
Example of Method Overriding

using System;
namespace Polymorphism2
{
    abstract class Test
    {
        public abstract void Message();

    }
    class Parent
    {
        public void Display()
        {
            Console.WriteLine("Display Method without parameter inside same class.");
        }
        public void Display(string s)
        {
            Console.WriteLine("{0} Display Method is overloaded inside same class.", s);
        }
        public virtual void Show() // virtual => overridable
        {
            Console.WriteLine("Show method is overridable.");
        }

    }
    class Child : Parent
    {
        public new void Display(string s)
        {
            Console.WriteLine("{0} Display Method is overloaded inside this Child class.", s);
        }
        public override void Show()
        {
            Console.WriteLine("Show method is overridden inside child class.");
        }
    }
    class Test2 : Test    
    {
        public override void Message() //abstract class mandatorily overridden to be consumed by inheriting class 
        {
            Console.WriteLine("abstract class method overidden.");
        }

    }

}

using System;
namespace Polymorphism2
{
    class Program
    {
        static void Main(string[] args)
        {
            Parent p = new Parent();
            p.Display("Hello!");
            p.Show();
            Child c = new Child();
            c.Display();
            c.Display("Hi!");
            c.Show();
            Test2 t = new Test2();
            t.Message();
            Console.ReadLine();
        }
    }
}

Edited on 5th July 2023

Hot Topics