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

Wednesday, November 15, 2017

Building .Net Core Apps for Docker


As mentioned in other posts about Docker, Docker is talk of the town. Docker is a containerization platform which fully lives up to it's motto - "Build, Ship, and Run Any App, Anywhere".

Docker containers provides an additional layer of abstraction on top of virtual machines we're familiar with. Simply put, Docker is a tool that can package an application and it's dependencies in a virtual container that can run on any server (Linux or Windows). This capability gives freedom from underlying operating system constraints and no longer can we say "It works on my machine!". 

New kid on the block ASP.NET Core provides first class Docker support owing it's inherit capability for cross-platform code. 

Visual Studio 2017 supports tooling for adding Docker support for brand new .Net Core Apps or existing .Net Framework apps. You may ask can we run existing Full .Net Framework apps on Docker? We can safely yes if your were to choose Windows containers. 

We must be living in an age of innovation. No time is better than now where we have fairly stable .NET Core 2.0 standard, matured .Net Core stacks (EF Core, ASP.NET Core 2.0) and a feature rich Docker support (did I say about multi-stage deployments).

If you're from .Net school,  you may be looking for a perfect tutorial to dip your toes into Docker world using .Net Core, we can happily recommend perfectly written, very detailed and any .Net programmer can get it. 

Excellent blog post by Maher Jendoubi on ASP.Net Core 2.0 in Docker is an excellent place to begin your Docker journey with .Net Core  stack.




C# code sample calculating US Holidays List for a given year programmatically

C# code sample to calculate US holidays list for any given year programmatically. All these holidays occur on a specific week in a month of year.

  •  MLK Day 
  •  President's Day 
  •  Memorial Day 
  •  Labor Day 
  •  Columbus Day 
  •  Thanksgiving Day

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
using System;
using System.Linq;

namespace holidayhelper
{
    class Program
    {
        static void Main(string[] args)
        {
            int year = 2017;
            Console.WriteLine("{0,-20}:{1}","MLK Day",HolidayHelper.MlkDay(year));
            Console.WriteLine("{0,-20}:{1}","Presidents Day",HolidayHelper.PresidentDay(year));
            Console.WriteLine("{0,-20}:{1}","Memorial Day",HolidayHelper.MemorialDay(year));
            Console.WriteLine("{0,-20}:{1}","Labor Day",HolidayHelper.LaborDay(year));
            Console.WriteLine("{0,-20}:{1}","Columbus Day",HolidayHelper.ColumbusDay(year));
            Console.WriteLine("{0,-20}:{1}","Thanks Giving Day",HolidayHelper.ThanksgivingDay(year));
        }
    }
    public static class HolidayHelper{
        //MLK Day - Jan
        public static string MlkDay(int year)
        {
            return NthDayOfMonth(year, 1, DayOfWeek.Monday, 3);
        }
        // President's Day - Feb
        public static string PresidentDay(int year)
        {
            return NthDayOfMonth(year, 2, DayOfWeek.Monday, 3);
        }
        //Memorial Day - May last week
        public static string MemorialDay(int year)
        {
            return LastMondayOfMay(year);
        }
        //Labor Day - Sept First week
        public static string LaborDay(int year)
        {
            return NthDayOfMonth(year, 9, DayOfWeek.Monday, 1);
        }
        ///Columbus Day - october second week
        public static string ColumbusDay(int year)
        {
            return NthDayOfMonth(year, 10, DayOfWeek.Monday, 2);
        }
        ///ThanksGiving Day - nov Fourth week
        public static string ThanksgivingDay(int year)
        {
            return NthDayOfMonth(year, 11, DayOfWeek.Thursday, 4);
        }
        
         /// <summary>
        /// returns the nth day of given month (like 1st monday of month, 3rd tuesday of month or 4th monday of month)
        /// </summary>
        /// <param name="year">input year</param>
        /// <param name="month">input month</param>
        /// <param name="dow">Day of week</param>
        /// <param name="n">nth day</param>
        /// <returns>Datetime for the nthday</returns>
        private static string NthDayOfMonth(int year, int month, DayOfWeek dow, int n)
        {
            var days = DateTime.DaysInMonth(year, month);
            var nthday = (from day in Enumerable.Range(1, days)
                let dt = new DateTime(year, month, day)
                where dt.DayOfWeek == dow && (day - 1) / 7 == (n - 1)
                select dt).FirstOrDefault();
            return nthday.ToShortDateString();
        }

         /// <summary>
        /// returns the last monday date for memorial day for the given year. 
        /// </summary>
        /// <param name="year">input year</param>
        /// <returns>Memorial day date</returns>
        private static string LastMondayOfMay(int year)
        {
            var dt = new DateTime(year, 5, 31);
            while (dt.DayOfWeek != DayOfWeek.Monday)
            {
                dt = dt.AddDays(-1);
            }
            return dt.ToShortDateString();
        }
    }
}

Sunday, April 9, 2017

C# code snippet for setting up a FileSystemWatcher on a directory or file

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System;
using System.IO;

 FileSystemWatcher watcher = new FileSystemWatcher();
 watcher.Path = @"C:\filedumps";
        /* Watch for changes in LastWrite times, and the renaming of files  */
        watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName;
        // watch text files
        watcher.Filter = "*.txt";
        // Add event handlers
        watcher.Changed += new FileSystemEventHandler(OnChanged);
        watcher.Renamed += new RenamedEventHandler(OnRenamed);

        // raise events
        watcher.EnableRaisingEvents = true;

    private static void OnChanged(object source, FileSystemEventArgs e)
    {
          Console.WriteLine("File: " +  e.FullPath + " " + e.ChangeType);
    }

    private static void OnRenamed(object source, RenamedEventArgs e)
    {
          Console.WriteLine("File: {0} renamed to {1}", e.OldFullPath, e.FullPath);
    }

C# code snippet for creating a self hosted WCF service

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 ServiceHost employeeServiceHost = null;
            try
            {
                //Base Address for EmployeeService
                Uri httpBaseAddress = new Uri("http://localhost:8080/EmployeeService");
                
                //Instantiate ServiceHost
                employeeServiceHost = new ServiceHost(typeof(Employee.EmployeeService),httpBaseAddress); 
 
               //Add Endpoint to Host
                employeeServiceHost.AddServiceEndpoint(typeof(EmployeeService.IEmployeeService),new WSHttpBinding(), "");            
 
               //Metadata Exchange
                ServiceMetadataBehavior serviceBehavior = new ServiceMetadataBehavior();
                serviceBehavior.HttpGetEnabled = true;
                employeeServiceHost.Description.Behaviors.Add(serviceBehavior);
 
                //Open
                employeeServiceHost.Open();
                Console.WriteLine("Employee Service is listening at : {0}", httpBaseAddress);
                Console.ReadKey();                
            }
            catch (Exception ex)
            {
                employeeServiceHost = null;
                Console.WriteLine(" An error occurred with EmployeeService" + ex.Message);
            }

C# code snippet for creating, extracting a compressed zip file

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
using System;
using System.IO;
using System.IO.Compression;
     
           string filePath = @"c:\temp\EmployeeInfo";
            string zipPath = @"c:\temp\EmployeeInfo.zip";
            string extractPath = @"c:\temp\extract";

            ZipFile.CreateFromDirectory(startPath, zipPath);

            ZipFile.ExtractToDirectory(zipPath, extractPath);

C# program to generate prime numbers from 1 to n

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static void IsPrime(int n)
  {

   foreach (var num in Enumerable.Range(2, n-1))
   {
    if (num == 2)
    {
     Console.WriteLine(num);
     continue;
    }
    var result = true;
    for (int i = 2; i <= (int)Math.Sqrt(num); i++)
    {
     if (num % i == 0)
     {
      result = false;
      break;
     }
    }
    if (result)
     Console.WriteLine(num);
   }
   
  }

C# program to test a number is prime or not

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static void IsPrime(int number)
  {

   if (number == 1 || number == 0)
   {
    Console.WriteLine(false);
    return;
   }

   if (number == 2)
   {
    Console.WriteLine(true);
    return;
   }
   for (int i = 2; i <= (int)Math.Sqrt(number); i++)
   {
    if (number % i == 0)
    {
     Console.WriteLine(false);
     return;
    }
   }
   Console.WriteLine(true);
  }

Sunday, October 30, 2016

Common Csharp dotnet Regex expressions for user input validation

Name Pattern Example
US zip code regex ^\d{5}(?:[-\s]\d{4})?$ 12345 or 12345-2345
Canadian zip code regex ^([ABCEGHJKLMNPRSTVXY]\d[ABCEGHJKLMNPRSTVWXYZ])\ {0,1}(\d[ABCEGHJKLMNPRSTVWXYZ]\d)$ M4B 1B4
US phone number regex \(?\d{3}\)?-? *\d{3}-? *-?\d{4} (123) 345-234
US Date (MM/dd/YYYY) regex ^(0?[1-9]|[12][0-9]|3[01])[\/](0?[1-9]|1[012])[\/]\d{4}$ 05/31/2016
24 Hour time regex ^(?:0?[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$ 13:12
12 Hour time regex (AM/PM) ^(([0]?[0-9]|1[0-2]):[0-5][0-9][ ][aApP][mM])|((1[3-9]|2[0-3]):[0-5][0-9])$ 7:00 AM
Url regex ^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$ http://www.test.com or www.test.com
IP address regex ^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$ 127.0.0.1
US social security number rgex ^([0-9]{3}[-]*[0-9]{2}[-]*[0-9]{4})*$ 123-09-2345

Saturday, December 14, 2013

Generic TryParse handler for generic .Net Lists



Following C# code sample is a Generic TryParse handler for generic value type 
lists in .Net.  Any character delimited list can be split and use safe TryParse against split list 
to ensure you have valid data.




using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericTryParsehandler
{
    /// <summary>
    /// Generic TryParsehandler to split and parse generic value type lists.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="value"></param>
    /// <param name="result"></param>
    /// <returns></returns>
    public delegate bool TryParseHandler<T>(string value, out T result);
    class Program
    {
        static void Main(string[] args)
        {
            var semiColonDelimitedDateInput = "01/01/2001;2/02/2012;05/31/2013;05/05/1992";
            var commaDelimitedIntInput = "3,4,5,6";
            var intresult = commaDelimitedIntInput.TryParseList<int>(new[] { ',' }, int.TryParse);
            var dateresult = semiColonDelimitedDateInput.TryParseList<DateTime>(new[] { ';' }, DateTime.TryParse);
            
            if (dateresult.Count > 0)
            {
                foreach (var element in dateresult)
                {
                    Console.WriteLine(element);
                }
            }
            else
            {
                Console.WriteLine("Your semiColonDelimitedDateInput cannot be parsed.");
            }
            Console.WriteLine("*******************************************************************");
            if (intresult.Count > 0)
            {
                foreach (var element in intresult)
                {
                    Console.WriteLine(element);
                }
            }
            else
            {
                Console.WriteLine("Your commaDelimitedIntInput cannot be parsed.");
            }
            Console.ReadLine();
        }
    }


    /// <summary>
    /// 
    /// </summary>

    public static class ExtensionMethods
{
        /// <summary>
        /// Generic handler to split and TryParse each item in the list. Handler supports value types.. 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="separator"></param>
        /// <param name="handler"></param>
        /// <returns></returns>
    public static List<T> TryParseList<T>(this string source, char[] separator, TryParseHandler<T> handler)
        where T : struct

    {
        var splitList = new List<T>();
        if (string.IsNullOrEmpty(source)) return splitList;

        var parsedString = source.Split(separator, StringSplitOptions.RemoveEmptyEntries).ToList();

        parsedString.ForEach(x =>
        {
            T result;
            if (handler(x, out result))
            {
                splitList.Add(result);
            }
        });

        return splitList.Count == parsedString.Count ? splitList : new List<T>();
    }
}
}

Wednesday, September 25, 2013

C# sample for Google Geocoding API (JSON output)




C# Google geocoding API (JSON output) sample


Geocoding is the process of converting addresses (like "300 n state st chicago IL") into geographic coordinates (like latitude 37.423021 and longitude -122.083739), which you can use to place markers or position the map.



The Google Geocoding API provides a direct way to access a these services via an HTTP request.


This service is generally designed for geocoding static (known in advance) addresses for placement of application content on a map;



A Geocoding API request must be of the following form:
http://maps.googleapis.com/maps/api/geocode/output?parameters
where output may be either of the following values:
  • json (recommended) indicates output in JavaScript Object Notation (JSON)
  • xml indicates output as XML
Required parameters
  • address — The address that you want to geocode.       or  latlng — The textual latitude/longitude value for which you wish to obtain the closest, human-readable address. 
  • sensor — Indicates whether or not the geocoding request comes from a device with a location sensor. This value must be either true or false.
JSON Output Formats
http://maps.googleapis.com/maps/api/geocode/json?address=300+n+state+st+chicago+Il&sensor=true&components=country:US
We've left the sensor parameter in this example as a variable true_or_false to emphasize that you must set this value to either true or false explicitly.
The JSON returned by this request is shown below. 
{
   "results" : [
      {
         "address_components" : [
            {
               "long_name" : "300",
               "short_name" : "300",
               "types" : [ "street_number" ]
            },
            {
               "long_name" : "North State Street",
               "short_name" : "N State St",
               "types" : [ "route" ]
            },
            {
               "long_name" : "River North",
               "short_name" : "River North",
               "types" : [ "neighborhood", "political" ]
            },
            {
               "long_name" : "Chicago",
               "short_name" : "Chicago",
               "types" : [ "locality", "political" ]
            },
            {
               "long_name" : "Cook",
               "short_name" : "Cook",
               "types" : [ "administrative_area_level_2", "political" ]
            },
            {
               "long_name" : "Illinois",
               "short_name" : "IL",
               "types" : [ "administrative_area_level_1", "political" ]
            },
            {
               "long_name" : "United States",
               "short_name" : "US",
               "types" : [ "country", "political" ]
            },
            {
               "long_name" : "60654",
               "short_name" : "60654",
               "types" : [ "postal_code" ]
            }
         ],
         "formatted_address" : "300 North State Street, Chicago, IL 60654, USA",
         "geometry" : {
            "location" : {
               "lat" : 41.8883461,
               "lng" : -87.6288376
            },
            "location_type" : "ROOFTOP",
            "viewport" : {
               "northeast" : {
                  "lat" : 41.8896950802915,
                  "lng" : -87.6274886197085
               },
               "southwest" : {
                  "lat" : 41.8869971197085,
                  "lng" : -87.63018658029151
               }
            }
         },
         "types" : [ "street_address" ]
      }
   ],
   "status" : "OK"
}

Note that the JSON response contains two root elements:
  • "status" contains metadata on the request. See Status Codes below.
  • "results" contains an array of geocoded address information and geometry information.
Generally, only one entry in the "results" array is returned for address lookups, though the geocoder may return several results when address queries are ambiguous.
Following C# sample queries Google GeoCoding API and parses json response to custom .Net object. We've utilized Json.Net framework to parsing json object. 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;
using System.IO;
using System.Net;
using System.Web;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Please enter the address to validate:");
            var address = Console.ReadLine();
            NetGoogleGeocoding geoCoder = new NetGoogleGeocoding();
            var response = geoCoder.GoogleGeocode(address);
            Console.WriteLine("*********** validation complete *****************");
            Console.WriteLine(string.Format("House Number ---- {0}",response.GeoCodes[0].HouseNumber));
            Console.WriteLine(string.Format("Street Address -- {0}",response.GeoCodes[0].StreetAddress));
            Console.WriteLine(string.Format("City ------------ {0}",response.GeoCodes[0].City));
            Console.WriteLine(string.Format("County ---------- {0}",response.GeoCodes[0].County));
            Console.WriteLine(string.Format("State ----------- {0}",response.GeoCodes[0].State));
            Console.WriteLine(string.Format("Zip ------------- {0}",response.GeoCodes[0].Zip));
            Console.WriteLine(string.Format("Country --------- {0}",response.GeoCodes[0].Country));
            Console.WriteLine(string.Format("Full Address ---- {0}",response.GeoCodes[0].FullAddress));
            if (response.GeoCodes[0].Types.Count() > 1)
            {
                Console.WriteLine(string.Format("Types ----------- {0},{1}", response.GeoCodes[0].Types[0], response.GeoCodes[0].Types[1]));
            }
            else
            {
                Console.WriteLine(string.Format("Types ----------- {0}", response.GeoCodes[0].Types[0]));
            }
            Console.WriteLine(string.Format("Location Type---- {0}",response.GeoCodes[0].LocationType));
            Console.WriteLine(string.Format("Latitude -------  {0}",response.GeoCodes[0].Latitude.ToString()));
            Console.WriteLine(string.Format("Longitude-------- {0}",response.GeoCodes[0].Longitude.ToString()));
            Console.WriteLine(string.Format("Status   -------- {0}", response.GeoCodes[0].Status));
            Console.ReadLine();
         }
    }
 /// 
 ///   .Net utility for google geocoding API
 /// 
 public class NetGoogleGeocoding {
        public GeocodeJsonResponse GoogleGeoCodeResponse;
  const string GoogleGeoCodeJsonServiceUrl = "http://maps.googleapis.com/maps/api/geocode/json?address={0}&sensor=true&components=country:US";
        public NetGoogleGeocoding()
        {
            GoogleGeoCodeResponse = new GeocodeJsonResponse()
            {
                GeoCodes = new List()
            };
  }
  /// 
  ///   Performs Geocode and returns Object
  /// 
  ///  
        public GeocodeJsonResponse GoogleGeocode(string address)
        {
            using (var cli = new WebClient())
            {
                var addressToValidate = string.Format(GoogleGeoCodeJsonServiceUrl, HttpUtility.UrlEncode(address));
                var response = cli.DownloadString(new Uri(addressToValidate));
                return HydrateJson(response);
           }
  }
  /// 
  /// generic method to read json values from json string
  /// 
  ///  
  ///  
  ///  
  static string GetJsonNodeValue(JToken token, string field) {
   return token["address_components"].Children().Any(x => x["types"].Values().Contains(field))
        ? token["address_components"].Children().First(x => x["types"].Values().Contains(field))["short_name"].Value()
        : string.Empty;
  }
        GeocodeJsonResponse HydrateJson(string jsonResponse)
        {
   var results = (JObject) JsonConvert.DeserializeObject(jsonResponse);
   foreach(
   var googleGeoCode in
      results["results"].Children().Select(
         token =>
   new Geocode {
      HouseNumber = GetJsonNodeValue(token, "street_number"),
      StreetAddress = GetJsonNodeValue(token, "route"),
      City = GetJsonNodeValue(token, "locality"),
      County = GetJsonNodeValue(token, "administrative_area_level_2"),
      State = GetJsonNodeValue(token, "administrative_area_level_1"),
      Zip = GetJsonNodeValue(token, "postal_code"),
      Country = GetJsonNodeValue(token, "country"),
      FullAddress = token["formatted_address"].Value(),
      Types = token["types"].Values().ToList(),
      LocationType = token["geometry"]["location_type"].Value(),
      Latitude = token["geometry"]["location"]["lat"].Value(),
      Longitude = token["geometry"]["location"]["lng"].Value(),
      Status = string.Format("{0}", token["geometry"]["location_type"].Value())
   })) {
    GoogleGeoCodeResponse.GeoCodes.Add(googleGeoCode);
   }
   return GoogleGeoCodeResponse;
  }
 }

    public class GeocodeJsonResponse
    {
        public List GeoCodes { get; set; }
    }
    public class Geocode
    {
        public string HouseNumber { get; set; }
        public string StreetAddress { get; set; }
        public string City { get; set; }
        public string County { get; set; }
        public string State { get; set; }
        public string Zip { get; set; }
        public string Country { get; set; }
        public string FullAddress { get; set; }
        public List Types { get; set; }
        public string LocationType { get; set; }
        public float Latitude { get; set; }
        public float Longitude { get; set; }
        public string Status { get; set; }
    }

}


Monday, October 26, 2009

C# Object oriented programming concepts

Object oriented programming is a successful paradigm shift from procedural world. Representing a real world entity through an object and encapsulating data and behavior together in an object are some of basics of OOPS world. Object oriented has showered us with many benefits esp. code re usability through inheritance and abstraction.  At the same time, we are pushed into complex world filled with classes, contracts, objects and relationships between them. Polymorphism, encapsulation, messaging, abstraction are OOPS concepts.

There are three kinds of relationships between objects

Association:  Simple relationship which relates two objects. Customer object is related to sales object. 

Aggregation: It is containment or composition model. Example: page class encompasses controls on the page.

Inheritance:  Defining specialized derived classes from preexisting generalized classes. It shows more of a parent-child relationship like vehicle -> car


Abstract classes and Interfaces:


A class can implement more than one interface but can only inherit from one abstract class. Since C# doesn't support multiple inheritance, interfaces are used to implement multiple inheritances. All elements in interfaces are public by default.

An abstract class can contain non-abstract methods. i.e methods with code in it.
An interface cannot contain non-abstract methods. Abstract classes SHOULD have atleast one method abstract and interfaces have all abstract methods.

Interfaces are used to define the peripheral abilities of a class. In other words both Human and Vehicle can inherit from a IMovable interface.

An abstract class defines the core identity of a class and there it is used for objects of the same type.

An abstract class can contain non-static member variables.
An interface cannot contain non-static member variables.

A derived class uses the keyword "Extends" for an abstract class.
A subclass uses the keyword "Implements" for an interface.

If the subclass extends an abstract class, it cannot extend any other class.
If the subclass implements an interface, it can implement any number of other interfaces.

If the various implementations only share method signatures then it is better to use interfaces ( Multiple behaviors for different conditions)

Abstract classes provide a simple and easy way to version our components. By updating the base class, all the inheriting classes are automatically updated with the change. In an interface, creation of additional functions will have an effect on its child classes due to the necessary implementations of interface methods in classes. Abstract classes should be used primarily for objects that are closely related, whereas interfaces are best suited for providing common functionality to unrelated classes.

Say there are two classes, bird and airplane, and both of them have methods called fly. It would be ridiculous for an airplane to inherit from the bird class just because it has fly() method. Rather, the fly() method should be defined as an interface and both bird and airplanes should implement that interface. If we want to provide common, implemented functionality among all implementations of component.

In VB.Net language, abstract classes are created using "MustInherit" keyword. In C#, we have "Abstract" keyword. Abstract class is designed to act as a base class. You cannot create a object of abstract class.

Shadowing:

When two elements in a program have same name, one of them can hide and shadow the other one. So in such cases the element which shadowed the main element is referenced.

Differences between overriding and shadowing:

  • Overriding redefines only the implementation while shadowing redefines the whole element.

Sealed classes:

The sealed modifier is used to prevent derivation from a class. An error occurs if a sealed class is specified as the base class of another class. A sealed class cannot also be an abstract class. In .Net Framework, string is a sealed class.

Virtual keyword: (Overridable)
They signify  that method and property can be overridden.

Static/Shared:

  • If you want an object to be shared between multiple instances you will use a static/shared class.
  • Static classes cannot be instantiated. By default, an object is created on the first method call to that object.
  • Static classes cannot be inherited. 
  • Static classes can have only static members.
  • Static classes can have only static constructor

Structures and classes:

  • Structures are value types and classes are reference types. So structures use stack and classes use heap. 
  • Structure members cannot be declared as protected, but class member can be.
  • You cannot define inheritance in structures.
  • Structures do not require constructors while classes require.
  • Objects created from classes are terminated using garbage collector while structures are not destroyed GC