100% found this document useful (1 vote)
3K views205 pages

C#.Net Core (NareshIT)

.NET is a development framework created by Microsoft that allows developers to create various types of applications. It provides a comprehensive programming model for building applications that can run on Windows, as well as Web, mobile and embedded/IoT devices. The .NET framework includes a large class library called Framework Class Library (FCL), ASP.NET web services framework, and CLR (Common Language Runtime) which manages the execution of .NET programs and provides memory management, security, type safety, and exception handling.

Uploaded by

Aniket Nsc0025
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (1 vote)
3K views205 pages

C#.Net Core (NareshIT)

.NET is a development framework created by Microsoft that allows developers to create various types of applications. It provides a comprehensive programming model for building applications that can run on Windows, as well as Web, mobile and embedded/IoT devices. The .NET framework includes a large class library called Framework Class Library (FCL), ASP.NET web services framework, and CLR (Common Language Runtime) which manages the execution of .NET programs and provides memory management, security, type safety, and exception handling.

Uploaded by

Aniket Nsc0025
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 205

Introduction to .

NET
What is Application Software?
Ans: Application software is commonly defined as any program or number of programs designed for end-users. In
that sense, any end user program can be called an “application.” People often use the term “application software”
to talk about bundles or groups of individual software applications, using a different term, “application program” to
refer to individual applications. Examples of application software include items like Notepad, WordPad, Microsoft
Word, Microsoft Excel, or any of the Web Browsers used to navigate the Internet, etc.

Another way to understand application software is, in a very basic sense, every program that you use on
your computer is a piece of application software. The operating system, on the other hand, is system software.
Historically, the application was generally born as computers evolved into systems where you could run a particular
codebase on a given operating system. Even social media platforms have come to resemble applications, especially
on our mobile phone devices, where individual applications are given the nickname “apps.” So while the term
“application software” can be used broadly, it’s an important term in describing the rise of sophisticated computing
environments.

How to develop Application software?


Ans: There are two basic camps of software development: Applications Development and Systems Development.
Applications Development is focused on creating programs that meet the users' needs. These can range from mobile
phone apps, video games, enterprise-level accounting software. Systems Development is focused on creating and
maintaining operating systems and to do this we need to familiar with some Programming Language. Thousands of
different programming languages have been created, and more are being created every year. Many programming
languages are written in an imperative form (i.e., as a sequence of operations to perform) while other languages use
the declarative form (i.e. the desired result is specified, not how to achieve it).

What is a Programming Language?


Ans: A programming language is a formal language comprising a set of instructions that produce various kinds of
output. Programming languages are used in computer programming to implement algorithms. Most programming
languages consist of instructions for computers. Since the early 1800s, programs have been used to direct the
behavior of machines such as Jacquard looms, music boxes and player pianos.

“A computer programming language is a language used to write computer programs, which involves a
computer performing some kind of computation or algorithm and possibly control external devices such as printers,
disk drives, robots, and so on.”

Anyone can come up with ideas, but a developer will be able to turn those ideas into something concrete.
Even if you only want to work on the design aspects of software, you should have some familiarity with coding and
be able to create basic prototypes. There are a huge variety of programming languages that we can learn.

Very early computers, such as Colossus is thus regarded as the world's first programmable, electronic,
digital computer, although it was programmed by switches and plugs and not by a stored program.

Slightly later, programs could be written in machine language, where the programmer writes each
instruction in a numeric form the hardware can execute directly. For example, the instruction to add the value in
two memory location might consist of 3 numbers: an “opcode” that selects the “add” operation, and two memory

1
locations. The programs, in decimal or binary form, were read in from punched cards, paper tape, and magnetic tape
or toggled in on switches on the front panel of the computer. Machine languages were later termed first-generation
programming languages (1GL).

The next step was development of so-called second-generation programming languages (2GL) or assembly
languages, which were still closely tied to the instruction set architecture of the specific computer. These served to
make the program much more human-readable and relieved the programmer of tedious and error-prone address
calculations.

The first high-level programming languages, or third-generation programming languages (3GL), were
written in the 1950s. John Mauchly's Short Code, proposed in 1949, was one of the first high-level languages ever
developed for an electronic computer. Unlike machine code, Short Code statements represented mathematical
expressions in understandable form. However, the program had to be translated into machine code every time it
ran, making the process much slower than running the equivalent machine code.

At the University of Manchester, Alick Glennie developed Autocode in the early 1950s. As a programming
language, it used a compiler to automatically convert the language into machine code. The first code and compiler
was developed in 1952 for the Mark 1 computer at the University of Manchester and is considered to be the first
compiled high-level programming language.

In 1954, FORTRAN was invented at IBM by John Backus. It was the first widely used high-level general
purpose programming language to have a functional implementation, as opposed to just a design on paper. It is still
a popular language for high-performance computing and is used for programs that benchmark and rank the world's
fastest supercomputers.

Another early programming language was devised by Grace Hopper in the US, called FLOW-MATIC. It was
developed for the UNIVAC I at Remington Rand during the period from 1955 until 1959. Hopper found that business
data processing customers were uncomfortable with mathematical notation, and in early 1955, she and her team
wrote a specification for an English programming language and implemented a prototype. The FLOW-MATIC
compiler became publicly available in early 1958 and was substantially complete in 1959. FLOW-MATIC was a major
influence in the design of COBOL.

COBOL an acronym for “common business-oriented language” is a compiled English-like computer


programming language designed for business use. It is imperative, procedural and, since 2002, object-oriented.
COBOL is primarily used in business, finance, and administrative systems for companies and governments. COBOL is
still widely used in applications deployed on mainframe computers, such as large-scale batch and transaction
processing jobs. But due to its declining popularity and the retirement of experienced COBOL programmers,
programs are being migrated to new platforms, rewritten in modern languages. Most programming in COBOL is now
purely to maintain existing applications.

Pascal is an imperative and procedural programming language, designed by Niklaus Wirth as a small,
efficient language intended to encourage good programming practices using structured programming and data
structuring. It is named in honor of the French mathematician, philosopher and physicist Blaise Pascal. Pascal
enabled defining complex data types and building dynamic and recursive data structures such as lists, trees and
graphs. Pascal has strong typing on all objects, which means that one type of data cannot be converted or interpreted
as another without explicit conversions.

2
C is a general-purpose, imperative procedural computer programming language supporting structured
programming, lexical variable scope, and recursion, with a static type system. By design, C provides constructs that
map efficiently to typical machine instructions. It has found lasting use in applications previously coded in assembly
language. Such applications include operating systems, various application software for computers that range from
super computers to PLCs and embedded systems. A successor to the programming language B, C was originally
developed at Bell Labs by Dennis Ritchie between 1972 and 1973 to construct utilities running on UNIX. It was applied
to re-implementing the kernel of the UNIX operating system. During the 1980s, C gradually gained popularity. It has
become one of the most widely used programming languages, with C compilers from various vendors available for
the majority of existing computer architectures and operating systems. C has been standardized by the ANSI since
1989 (ANSI C) and by the International Organization for Standardization (ISO).

C++ is a general-purpose programming language developed by Danish computer scientist Bjarne Stroustrup
at Bell Labs since 1979 as an extension of the C programming language, or "C with Classes" as he wanted an efficient
and flexible language similar to C that also provided high-level features for program organization. The language has
expanded significantly over time, and modern C++ now has object-oriented, generic, and functional features in
addition to facilities for low-level memory manipulation. It is almost always implemented as a compiled language,
and many vendors provide C++ compilers, including the Free Software Foundation, LLVM, Microsoft, Intel, Oracle,
and IBM, so it is available on many platforms. C++ has also been found useful in many contexts, with key strengths
being software infrastructure and resource-constrained applications, including desktop applications, video games,
servers (e.g. e-commerce, Web search, or SQL Servers), and performance-critical applications (e.g. telephone
switches or space probes).

Objective-C is a general-purpose, object-oriented programming language that adds Smalltalk-style


messaging to the C programming language. It was the main programming language supported by Apple for macOS,
iOS, and their respective application programming interfaces (APIs). The language was originally developed in the
early 1980s. It was later selected as the main language used by NeXT for its NeXTSTEP operating system, from which
macOS and iOS are derived. Objective-C source code 'implementation' program files usually have .m filename
extensions, while Objective-C 'header/interface' files have .h extensions, the same as C header files. Objective-C++
files are denoted with a .mm file extension.

Python is an interpreted, high-level, general-purpose programming language. Created by Guido van Rossum
and first released in 1991. Its language constructs and object-oriented approach aim to help programmers write
clear, logical code for small and large-scale projects. Python is dynamically typed and garbage-collected. It supports
multiple programming paradigms, including structured (particularly, procedural), object-oriented, and functional
programming. Python was conceived in the late 1980s as a successor to the ABC language. Python 2.0 released in
2000 and Python 3.0, released in 2008, was a major revision of the language that is not completely backward-
compatible, i.e. Python 2 code does not run unmodified on Python 3. The Python 2 language was officially
discontinued in 2020 (first planned for 2015) and now only Python 3.5.x and later are supported.

Java is a general-purpose programming language that is class-based and object-oriented, and designed to
have as few implementation dependencies as possible. It is intended to let application developers write once, run
anywhere (WORA), meaning that compiled Java code can run on all platforms that support Java without the need of
recompilation. Java applications are typically compiled to byte code that can run on any Java virtual machine (JVM)
regardless of the underlying computer architecture. The syntax of Java is similar to C and C++. Java was originally
developed by James Gosling at Sun Microsystems (which has since been acquired by Oracle) and released in 1995 as
a core component of Sun Microsystems' Java platform.

3
C# (pronounced see sharp, like the musical note C♯, but written with the number sign) is a general-purpose,
multi-paradigm programming language encompassing strong typing, lexically scoped, imperative, declarative,
functional, generic, object-oriented (class-based), and component-oriented programming disciplines. It was
developed around 2000 by Microsoft as part of its .NET initiative and later approved as an international standard by
ECMA in 2002 and ISO in 2003. C# was designed by Anders Hejlsberg, and its development team is currently led by
“Mads Torgersen”. The most recent version is 8.0, which was released in 2019 alongside Visual Studio 2019 version
16.3 (a preview version of C# 9.0 was released in 2020 with Visual Studio 2019 version 16.6).
What is .NET?
Ans: .NET is a free, cross-platform, open source developer platform for building many different types of applications
like Desktop, Web, Mobile, Games and IOT by using multiple languages, editors, and libraries.

What is a Platform?
Ans: It is the environment in which a piece of software is executed. A platform can also be called as the stage on
which computer programs can run. Platform can refer to the type of processor (CPU) on which a given operating
system runs, the type of operating system on a computer or the combination of the type of hardware and the type
of operating system running on it. An example of a common platform is Microsoft Windows running on x86
architecture. Other well-known desktop computer platforms include Linux/Unix and macOS

What is Cross-platform?
Ans: In computing, cross-platform software (also multi-platform software or platform-independent software) is
computer software that is implemented to run on multiple platforms. For example, a cross-platform application may
run on Microsoft Windows, Linux, and macOS. Cross-platform programs may run on as many as all existing platforms,
or on few platforms.

What is meant by developing applications using multiple languages?


Ans: .NET languages are programming languages that are used to produce libraries and programs that conform to
the Common Language Infrastructure (CLI) specifications. Most of the CLI languages compile entirely to the Common
Intermediate Language (CIL), an intermediate language that can be executed using the Common Language Runtime,
implemented by .NET Framework, .NET Core, and Mono. As the program is being executed, the CIL code is just-in-
time compiled to the machine code appropriate for the architecture on which the program is running. While there
are currently over 30+ languages in .NET, but only a small number of them are widely used and supported by
Microsoft. List of .NET languages include: C#, F#, Visual Basic, C++, Iron Python, etc and the most popular and widely
used language as a developer choice is C#. Visit the following link to view the list of .NET Languages:
https://microsoft.fandom.com/wiki/Microsoft_.NET_Languages

What is CLI (Common Language Infrastructure)?


Ans: The Common Language Infrastructure (CLI) is an open specification (technical standard) developed by Microsoft
and standardized by ISO (International Organization for Standardization) and ECMA (European Computer
Manufacturers Association) that describes about executable code and a runtime environment that allows multiple
high-level languages to be used on different computer platforms without being rewritten for specific architectures.
This implies it is platform independent. The .NET Framework, .NET Core and Mono are implementations of the CLI.

CLI specification describes the following four aspects:


1. The Common Language Specification (CLS): A set of base rules to which any language targeting the CLI
should conform in order to interoperate to other CLS-compliant languages. The CLS rules define a subset of
the Common Type System.

4
2. The Common Type System (CTS): A set of data types and operations that are shared by all CTS-compliant
programming languages. According to this all .NET Languages has to adopt the rule “Uniform Data Type
Structure” i.e. similar data types must be same in size in all Languages of .NET.

3. The Metadata: Information about program structure is language - independent, so that it can be referenced
between languages and tools’, making it easy to work with code written in a language the developer is not
aware.

4. The Virtual Execution System (VES): The VES loads and executes CLI-compatible programs. All compatible
.NET languages compile to Common Intermediate Language (CIL), which is an intermediate code that is
abstracted from the platform hardware. When the code is executed, the platform-specific VES will compile
the CIL to the machine language according to the specific hardware and operating system.

What is .NET Framework and .NET Core?


Ans: .NET is a developer platform made up of tools, programming languages, and libraries for building many different
types of applications. There are various implementations of .NET and each implementation allows .NET code to
execute in different places - Linux, macOS, Windows, iOS, Android, and many more. Various implementations of the
.NET include:
1. .NET Framework: it is the original implementation of .NET and it supports running websites, services,
desktop apps, and more on Windows.
2. .NET Core: it is a cross-platform implementation for running websites, services, and console apps on
Windows, Linux, and macOS.
3. Xamarin/Mono: it is a .NET implementation for running apps on all the major mobile operating systems,
including iOS and Android.
Architecture of .NET Framework: The two major components of .NET Framework are the .NET Framework Class
Library and the Common Language Runtime.

1. The Class Library provides a set of APIs and types for common functionality. It provides types for strings,
dates, numbers, etc. The Class Library includes APIs for reading and writing files, connecting to databases,
drawing, and more.
2. The Common Language Runtime (CLR) is the heart of .NET Framework and the execution engine that
handles running applications. It provides services like thread management, garbage collection, type-safety,
exception handling, and more.

Architecture of .NET Framework CLR:

5
.NET applications can be written in any .NET Language like C#, F#, or Visual Basic. Source Code we write by
using some .NET Language is compiled into a language-agnostic Common Intermediate Language (CIL) and the
compiled code is stored as assemblies (files with a “.dll” or “.exe” extension). When we run the applications, CLR
takes the assemblies and uses a just-in-time compiler (JIT) to turn it into machine code that can execute on the
specific architecture of the computer it is running on.

.NET Framework FAQ’s


What is .NET Framework used for?
Ans: .NET Framework is used to create and run software applications. .NET apps can run on many operating systems,
using different implementations of .NET. .NET Framework is used for running .NET apps on Windows.

Who uses .NET Framework?


Ans: Software developers and the users of their applications both use .NET Framework:
• Users need to install .NET Framework to run application built with the .NET Framework. In most cases, .NET
Framework is already installed with Windows. If needed, you can download .NET Framework.
• Software developers use .NET Framework to build many different types of applications - websites, services,
desktop apps, and more with Visual Studio. Visual Studio is an integrated development environment (IDE)
that provides development productivity tools and debugging capabilities. See the .NET customer showcase
for examples of what people are building with .NET.

Why do I need .NET Framework?


Ans: You need .NET Framework installed in order to run applications on Windows that were created using .NET
Framework. It is already included in many versions of Windows. You only need to download and install .NET
Framework if prompted to do so.

How does .NET Framework work?


Ans: .NET Framework applications can be written in many languages like C#, F#, or Visual Basic and compiled to
Common Intermediate Language (CIL). The Common Language Runtime (CLR) runs .NET applications on a given
machine, converting the CIL to machine code. See Architecture of .NET Framework for more info.

What are the main components/features of .NET Framework?


Ans: The two major components of .NET Framework are the Common Language Runtime (CLR) and the .NET
Framework Class Library. The CLR is the execution engine that handles running applications. The Class Library
provides a set of APIs and types for common functionality.

6
How many versions do we have for .NET Framework?
Ans: There are multiple versions of .NET Framework but each new version adds new features but retains features
from previous versions. List of .NET Framework Versions:
.NET Framework 1.0 .NET Framework 1.1 .NET Framework 2.0 .NET Framework 3.0
.NET Framework 3.5 .NET Framework 4 .NET Framework 4.5 .NET Framework 4.5.1
.NET Framework 4.5.2 .NET Framework 4.6 .NET Framework 4.6.1 .NET Framework 4.6.2
.NET Framework 4.7 .NET Framework 4.7.1 .NET Framework 4.7.2 .NET Framework 4.8

Can you have multiple .NET Frameworks installed?


Ans: Some versions of .NET Framework are installed side-by-side, while others will upgrade an existing version
(known as an in-place update). In-place updates occur when two .NET Framework versions share the same CLR
version. For example, installing .NET Framework 4.8 on a machine with .NET Framework 4.7.2 and 3.5 installed will
perform an in-place update of the 4.7.2 installation and leave 3.5 installed separately.
.NET Framework Version CLR Version
.NET Framework 4.x 4.0
.NET Framework 2.x and 3.x 2.0
.NET Framework 1.1 1.1
.NET Framework 1.0 1.0

How much does .NET Framework cost?


Ans: .NET Framework is free, like the rest of the .NET platform. There are no fees or licensing costs, including for
commercial use.

Which version of .NET Framework should I use?


Ans: In most cases, you should use the latest stable release and currently, that's .NET Framework 4.8. Applications
that were created with any 4.x version of .NET Framework will run on .NET Framework 4.8. To run an application
that was created for an earlier version (for example, .NET Framework 3.5), you should install that version.

What is the support policy for .NET Framework?


Ans: .NET Framework 4.8 is the latest version of .NET Framework and will continue to be distributed with future
releases of Windows. As long as it is installed on a supported version of Windows, .NET Framework 4.8 will continue
to also be supported.

Can customers continue using the .NET Framework and get support?
Ans: Yes. Many products both within and outside Microsoft rely on .NET Framework. The .NET Framework is a
component of Windows and receives the same support as Windows version which it ships with or on which it is
installed. .NET Framework 4.8 is the latest version of .NET Framework and will continue to be distributed with future
releases of Windows. As long as it is installed on a supported version of Windows, .NET Framework 4.8 will continue
to also be supported.

Architecture of .NET Core: The two main components of .NET Core are CoreCLR and CoreFX, respectively, which are
comparable to the Common Language Runtime (CLR) and the Framework Class Library (FCL) of the .NET Framework's
Common Language Infrastructure (CLI) implementation.
1. CoreFX is the foundational class libraries for .NET Core. It includes types for collections, file systems,
console, JSON, XML and many others.

7
2. CoreCLR is the .NET execution engine in .NET Core, performing functions such as garbage collection and
compilation to machine code. As a CLI implementation of Virtual Execution System (VES), CoreCLR is a
complete runtime and virtual machine for managed execution of .NET programs and includes a just-in-time
compiler called RyuJIT.
Note: .NET Core releases have a single product version, that is, there is no separate CLR version.

What is CoreFX?
Ans: CoreFX, also referred to as the Unified Base Class Library, consists of the basic and fundamental classed that
form the core of the .Net Core platform. These set of libraries comprise the System.* (and to a limited extent
Microsoft.*) namespaces. Majority of the .NET Core APIs are also available in the .NET Framework, so you can think
of CoreFX as an extension of the .NET Framework Class Library.

What is CoreCLR?
Ans: CoreCLR is the .NET execution engine in .NET Core which is a complete runtime and virtual machine for managed
execution of .NET programs and includes a just-in-time compiler called RyuJIT, performing functions such as garbage
collection and compilation to machine code. CoreCLR is built from the same code base of the Framework CLR.

What is Roslyn?
Ans: Roslyn is the codename-that-stuck for the open-source compiler for C# and Visual Basic.NET. It is an open
source, cross-platform, public language engine for C# and VB. The conversations about Roslyn were already ongoing
when “Mads Torgersen” joined Microsoft in 2005 - just before .NET 2.0 would ship. That conversation was about
rewriting C# in C# which is a normal practice for programming languages. But there was a more practical and
important motivation: the creators of C# were not programming in C# themselves, they were coding in C++.
.NET CORE FAQ’s
What is .NET Core?
Ans: The .NET Core platform is a new .NET stack that is optimized for open source development. .NET Core has two
major components. It includes a runtime that is built from the same codebase as the .NET Framework CLR. The .NET
Core runtime includes the same GC and JIT (RyuJIT), but doesn’t include features like Application Domains or Code
Access Security. .NET Core also includes the base class libraries. These libraries are the same code as the .NET
Framework class libraries, but have been factored to enable to ship as smaller set of libraries. .NET Core refers to
several technologies including ASP.NET Core, Entity Framework Core, and more.

What are the characteristics of .NET Core?


Ans: .NET Core has the following characteristics:
• Cross platform: Runs on Windows, macOS, and Linux operating systems.
• Open source: The .NET Core framework is open source, using MIT and Apache 2 licenses. .NET Core is a
.NET Foundation project.
• Modern: It implements modern paradigms like asynchronous programming, no-copy patterns using struts’,
and resource governance for containers.

8
• Performance: Delivers high performance with features like hardware intrinsics, tiered compilation, and
Span<T>.
• Consistent across environments: Runs your code with the same behavior on multiple operating systems
and architectures, including x64, x86, and ARM.
• Command-line tools: Includes easy-to-use command-line tools that can be used for local development and
for continuous integration.
• Flexible deployment: You can include .NET Core in your app or install it side-by-side (user-wide or system-
wide installations). Can be used with Docker containers.

What is the composition of .NET Core?


Ans: NET Core is composed of the following parts:
• The .NET Core runtime, which provides a type system, assembly loading, a garbage collector, native interop,
and other basic services. .NET Core framework libraries provide primitive data types, app composition
types, and fundamental utilities.
• The ASP.NET Core runtime, which provides a framework for building modern, cloud-based, internet-
connected apps, such as web apps, IOT apps, and mobile backend.
• The .NET Core SDK and language compilers (Roslyn and F#) that enable the .NET Core developer experience.
• The dotnet command, which is used to launch .NET Core apps and CLI commands. It selects and hosts the
runtime, provides an assembly loading policy, and launches apps and tools.

What is .NET Core SDK?


Ans: The .NET Core SDK (Software Development Kit) includes everything you need to build and run .NET Core
applications using command line tools or any editor like Visual Studio. It also contains a set of libraries and tools that
allow developers to create .NET Core applications and libraries. It contains the following components that are used
to build and run applications:
1. The .NET Core CLI.
2. .NET Core libraries and runtime.
3. The dotnet driver.

What is .NET Core Runtime?


Ans: This includes everything you need to run a .NET Core Application. The runtime is also included in the SDK. When
an app author publishes an app, they can include the runtime with their app. If they don't include the runtime, it's
up to the user to install the runtime. There are three different runtimes you can install on Windows:
• ASP.NET Core runtime: Runs ASP.NET Core apps. Includes the .NET Core runtime.
• Desktop runtime: Runs .NET Core WPF and .NET Core Windows Forms desktop apps for Windows. Includes
the .NET Core runtime.
• .NET Core runtime: This runtime is the simplest runtime and doesn't include any other runtime. It's highly
recommended that you install both ASP.NET Core runtime and Desktop runtime for the best compatibility
with .NET Core apps.

What's the difference between SDK and Runtime in .NET Core?


Ans: The SDK is all of the stuff that is needed for developing a .NET Core application easier, such as the CLI and a
compiler. The runtime is the “virtual machine” that hosts/runs the application and abstracts all the interaction with
the base operating system.
What is the difference between .NET Core and .NET Framework?

9
Ans: .NET Core and .NET Framework share many of the same components and you can share code across the two.
Some key differences include:
• .NET Core is cross-platform and runs on Linux, macOS, and Windows. .NET Framework only runs on
Windows.
• .NET Core is open-source and accepts contributions from the community. The .NET Framework source code
is available, but does not take direct contributions.
• The majority of .NET innovation happens in .NET Core.
• .NET Framework is included in Windows and automatically updated machine-wide by Windows Update.
.NET Core is shipped independently.

What is the difference between .NET Core and Mono?


Ans: To be simple, Mono is third party implementation of .Net Framework for Linux/Android/iOS and .Net Core is
Microsoft's own implementation for same.

What's the difference between .NET Core, .NET Framework, and Xamarin?
Ans: difference between .NET Core, .NET Framework and Xamarin are:
• .NET Framework is the “traditional” flavor of .NET that's distributed with Windows. Use this when you are
building a desktop Windows or UWP app, or working with older ASP.NET 4.8.
• .NET Core is cross-platform .NET that runs on Windows, Mac, and Linux. Use this when you want to build
console or web apps that can run on any platform, including inside Docker containers.
• Xamarin is used for building mobile apps that can run on iOS, Android, or Windows Phone devices.

What is the support policy to .NET Core?


Ans: .NET Core is supported by Microsoft on Windows, macOS, and Linux. It's updated for security and quality
regularly (the second Tuesday of each month). .NET Core binary distributions from Microsoft are built and tested on
Microsoft-maintained servers in Azure and follow Microsoft engineering and security practices.

Red Hat supports .NET Core on Red Hat Enterprise Linux (RHEL). Red Hat builds .NET Core from source and makes it
available in the Red Hat Software Collections. Red Hat and Microsoft collaborate to ensure that .NET Core works well
on RHEL (Red Hat Enterprise Linux).

Tizen (developed by Samsung) supports .NET Core on Tizen platforms.

How much does .NET Core cost?


Ans: .NET Core is an open-source and cross-platform version of .NET that is maintained by Microsoft and the .NET
community on GitHub. All aspects of .NET Core are open-source including class libraries, runtime, compilers,
languages, ASP.NET Core web framework, Windows desktop frameworks, and Entity Framework Core data access
library. There are no licensing costs, including for commercial use.
What is GitHub?

10
Ans: GitHub is a code hosting platform for collaboration and version control. It is a repository (usually abbreviated
to “repo”) is a location where all the files for a particular project are stored which lets you (and others) work together
on projects. Each project has its own repo, and you can access it with a unique URL. Git is an open-source version
control system that was started by “Linus Torvalds” - the same person who created Linux. Git is similar to other
version control systems—Subversion, CVS, and Mercurial to name a few.

What is the release schedule for .NET Core?


Ans: .NET Core 2.1 and .NET Core 3.1 are the current LTS releases made available on August 2018 and December
2019, respectively. After .NET Core 3.1, the product will be renamed to .NET and LTS releases will be made available
every other year in November. So, the next LTS release will be .NET 6, which will ship in November 2021. This will
help customers plan upgrades more effectively.

How many versions do we have for .NET Core?


Ans: This table tracks release dates and end of support dates for .NET Core versions.
Version Original Release Date Support Level End of Support
.NET Core 3.1 December 3, 2019 LTS December 3, 2022
.NET Core 3.0 September 23, 2019 EOL March 3, 2020
.NET Core 2.2 December 4, 2018 EOL December 23, 2019
.NET Core 2.1 May 30, 2018 LTS August 21, 2021
.NET Core 2.0 August 14, 2017 EOL October 1, 2018
.NET Core 1.1 November 16, 2016 EOL June 27, 2019
.NET Core 1.0 June 27, 2016 EOL June 27, 2019

EOL (end of life) releases have reached end of life, meaning it is not longer supported and recommended moving to
a supported version.
LTS (long-term support) releases have an extended support period. Use this if you need to stay supported on the
same version of .NET Core for longer.
.NET 5 (.NET Core vNext)
.NET 5 is the next step forward with .NET Core. This new project and direction are a game-changer for .NET. With
.NET 5, your code and project files will look and feel the same no matter which type of app you’re building. You’ll
have access to the same runtime, API and language capabilities with each app. The project aims to improve .NET in
a few key ways:
• Produce a single .NET runtime and framework that can be used everywhere and that has uniform runtime
behaviors and developer experiences.
• Expand the capabilities of .NET by taking the best of .NET Core, .NET Framework, Xamarin and Mono.
• Build that product out of a single code-base that developers (Microsoft and the community) can work on
and expand together and that improves all scenarios.

Microsoft skipped the version 4 because it would confuse users that are familiar with the .NET Framework,
which has been using the 4.x series for a long time. Additionally, they wanted to clearly communicate that .NET 5 is
the future for the .NET platform. They are also taking the opportunity to simplify naming. They thought that if there
is only one .NET going forward, they don’t need a clarifying term like “Core”. The shorter name is a simplification
and also communicates that .NET 5 has uniform capabilities and behaviors. Feel free to continue to use the “.NET
Core” name if you prefer it.
Runtime experiences:

11
Mono is the original cross-platform implementation of .NET. It started out as an open-source alternative to
.NET Framework and transitioned to targeting mobile devices as iOS and Android devices became popular. Mono is
the runtime used as part of Xamarin.

CoreCLR is the runtime used as part of .NET Core. It has been primarily targeted at supporting cloud
applications, including the largest services at Microsoft, and now is also being used for Windows desktop, IoT and
machine learning applications.

Taken together, the .NET Core and Mono runtimes have a lot of similarities (they are both .NET runtimes
after all) but also valuable unique capabilities. It makes sense to make it possible to pick the runtime experience you
want. They are in the process of making CoreCLR and Mono drop-in replacements for one another and will make it
as simple as a build switch to choose between the different runtime options.

.NET Schedule: .NET 5 will ship in November 2020, and then they intend to ship a major version of .NET once a year,
every November:

The .NET 5 project is an important and exciting new direction for .NET. You will see .NET become simpler
but also have broader and more expansive capability and utility. All new development and feature capabilities will
be part of .NET 5, including new C# versions. We see a bright future ahead in which you can use the same .NET APIs
and languages to target a broad range of application types, operating systems, and chip architectures. It will be easy
to make changes to your build configuration to build your applications differently, in Visual Studio, Visual Studio for
Mac, Visual Studio Code, and Azure DevOps or at the command line.

12
C# Programming Langauge
C# (pronounced see sharp, like the musical note C♯, but written with the number sign is a general-purpose,
programming language encompassing strong typing, lexically scoped, imperative, declarative, functional, generic,
object-oriented (class-based), and component-oriented programming disciplines. It was developed around 2000 by
Microsoft as part of its .NET initiative and later approved as an international standard by Ecma in 2002 and ISO in
2003.

The name "C Sharp" was inspired by the musical notation where a sharp indicates that the written note
should be made a semitone higher in pitch. This is similar to the language name of C++, where "++" indicates that a
variable should be incremented by 1 after being evaluated. The sharp symbol also resembles a ligature of four "+"
symbols (in a two-by-two grid), further implying that the language is an increment of C++. Due to technical limitations
of display and the fact that the sharp symbol is not present on most keyboard layouts, the number sign was chosen
to approximate the sharp symbol in the written name of the programming language.

C# was designed by Anders Hejlsberg, and its development team is currently led by Mads Torgersen. C# has
Procedural, Object Oriented syntax based on C++ and includes influences from several programming languages, most
importantly Delphi and Java with a particular emphasis on simplification. The most recent stable version is 8.0, which
was released in 2019 and preview version of 9.0 was released in My 20, 2020.

History: During the development of the .NET Framework, the class libraries were originally written using a managed
code compiler system called "Simple Managed C" (SMC). In January 1999, Anders Hejlsberg formed a team to build
a new language at the time called Cool, which stood for "C-like Object Oriented Language". Microsoft had considered
keeping the name "Cool" as the final name of the language, but chose not to do so for trademark reasons. By the
time .NET project was publicly announced at the July 2000 Professional Developers Conference, the language had
been renamed C#, and the class libraries and ASP.NET runtime had been ported to C#. Anders Hejlsberg is C#'s
principal designer and lead architect at Microsoft, and was previously involved with the design of Turbo Pascal,
Borland Delphi and Visual J++. In interviews and technical papers he has stated that flaws in most major
programming languages (e.g. C++, Java, Delphi, and Smalltalk) drove the design of the C# language.

Design Goals: The Ecma standard lists these design goals for C#.

• The language is intended to be a simple, modern, general-purpose, object-oriented programming language.


• The language, and implementations thereof, should provide support for software engineering principles
such as strong type checking, array bounds checking, detection of attempts to use uninitialized variables,
and automatic garbage collection.
• The language is intended for use in developing software components suitable for deployment in distributed
environments.
• Portability is very important for source code and programmers, especially those already familiar with C and
C++.
• Support for internationalization is very important.
• C# is intended to be suitable for writing applications for both hosted and embedded systems, ranging from
the very large that use sophisticated operating systems, down to the very small having dedicated functions.
Versions: 1.0, 1.2, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 (Preview Release).
New features in C# 2.0:
➢ Generics

13
➢ Partial types
➢ Anonymous methods
➢ Iterators
➢ Nullable value types
➢ Getter/setter separate accessibility
➢ Static classes
➢ Delegate inference
➢ Null coalescing operator

New features in C# 3.0:


➢ Implicitly typed local variables
➢ Object and collection initializers
➢ Auto-Implemented properties
➢ Anonymous types
➢ Extension methods
➢ Query expressions
➢ Lambda expressions
➢ Expression trees
➢ Partial methods

New features in C# 4.0:


➢ Dynamic binding
➢ Named and optional arguments
➢ Generic covariant and contravariant
➢ Embedded interop types

New features in C# 5.0:


➢ Asynchronous methods
➢ Caller info attributes

New features in C# 6.0:


➢ Static imports
➢ Exception filters
➢ Auto-property initializers
➢ Default values for getter-only properties
➢ Expression bodied members
➢ Null propagator
➢ String interpolation
➢ nameof operator
➢ Index initializers

New features in C# 7.0:


➢ Out variables
➢ Tuples and deconstruction
➢ Pattern matching
➢ Local functions

14
➢ Expanded expression bodied members
➢ Ref locals and returns
➢ Discards
➢ Binary Literals and Digit Separators
➢ Throw expressions

New features in C# 7.1:


➢ Async main method
➢ Default literal expressions
➢ Inferred tuple element names
➢ Pattern matching on generic type parameters

New features in C# 7.2:


➢ Techniques for writing safe efficient code
➢ Non-trailing named arguments
➢ Leading underscores in numeric literals
➢ private protected access modifier
➢ Conditional ref expressions

New features in C# 7.3:


➢ Accessing fixed fields without pinning
➢ Reassigning ref local variables
➢ Using initializers on stackalloc arrays
➢ Using fixed statements with any type that supports a pattern
➢ Using additional generic constraints

New features in C# 8.0:


➢ Readonly members
➢ Default interface methods
➢ Pattern matching enhancements:
▪ Switch expressions
▪ Property patterns
▪ Tuple patterns
▪ Positional patterns
➢ Using declarations
➢ Static local functions
➢ Disposable ref structs
➢ Nullable reference types
➢ Asynchronous streams
➢ Indices and ranges
➢ Null-coalescing assignment
➢ Unmanaged constructed types
➢ Stackalloc in nested expressions
➢ Enhancement of interpolated verbatim strings
Writing a program by using different Programming Approaches

15
To write a program we generally follow 2 different approaches in the industry:
1. Procedural Programming Approach
2. Object Oriented Programming Approach

Procedural Programming Approach: This is a very traditional approach followed by the industry to develop
applications till 70's. E.g.: COBOL, Pascal, FORTRAN, C, etc.

In this approach a program is a collection of members like variables and functions, and the members that
are defined inside the program should be explicitly called for execution and we do that calling from “main” function
because it is the entry point of any program that is developed by using any programming language.

Note: the drawbacks of procedural programming languages are they don't provide security and re-usability.
Object Oriented Programming Approach: This came into existence in 70's to overcome the drawbacks of Procedural
Programming Language’s by providing Security and Re-usability.
E.g.: CPP, Python, Java, C#, etc.
In an Object Oriented Programming approach also a program is a Collection of members like variables and
functions only, but the main difference between Object Oriented Languages and Procedural Languages is, here to
protect the members of a program we put them under a container or wrapper known as a "class".

What is a class?
Ans: it is a user-defined type very much similar to structures we have learnt in C language, i.e. by using these we can
define new types, whereas the difference between the two are, structure in “C” language can contain only variables
in it but class of Object Oriented languages can contain both variables and functions also.

Syntax to define Class and Structure:


struct <Name> class <Name>
{ {
-Variables -Variables
}; -Functions
};
Example:

16
struct Student class Employee
{ {
int Id; int Id;
char Name[25]; string Name, Job;
float Marks, Fees; float Salary;
}; -Can be defined with functions also
};

In the above case int, float and char are pre-defined structures whereas string is a pre-defined class which
we are calling them as types, same as that Student and Employee are also types (user-defined). The other difference
between int, float, char and string types, as well as Student and Employee types is the 1st 4 are scalar types which
can hold 1 and only 1 value under them whereas the next 2 are complex types which can hold more than 1 value
under them.

How to consume a type?


Ans: types can't be consumed directly because they do not have any memory allocation.
int = 100; //Invalid

So to consume a type first we need to create a copy of that type:


int i = 100; //Valid

Note: In the above case “i” is a copy of pre-defined type int for which memory gets allocated and the above rule of
types can't be consumed directly, applies both to pre-defined and user-defined types also.
int i; //i is a copy of pre-defined type int
string s; //s is a copy of pre-defined type string
Student ss; //ss is a copy of user-defined type Student
Employee emp; //emp is a copy of user-defined type Employee

Note: Generally copies of scalar types like int, float, char, bool, string, etc. are known as variables, whereas copies
of complex types which we have defined like Student and Employee are known as Objects or Instances.

Conclusion: After defining a class or structure if we want to consume them, first we need to create a copy of them
and then only the memory which is required for execution gets allocated and by using that copy (Object or Instance)
only we can call members that are defined under them.

Note: CPP is the first Object Oriented Programming Language which came into existence, but still it suffers from a
criticism that it is not fully Object Oriented Language; because in CPP Language we can't write main function inside
of the class and according to the standards of Object Oriented Programming each and every Member of the Program
should be inside of the class.

17
The reason why we write main function outside of class is, if it is defined inside of the class then it becomes
a member of that class and members of a class can be called only by using object of that class, but un-fortunately
we create object of class inside main function only, so until and unless object of class is created main function can't
be called and at the same time until and unless main function starts it's execution, object creation will not take place
and this is called as "Circular Dependency" and to avoid this problem, in CPP Language we write main function
outside of the class.
Object Oriented Programming in Java: Java language came into existence in the year 1995 and here also a class is a
collection of members like variables and methods. While designing the language, designers have taken it as a
challenge that their language should not suffer from the criticism that it is not fully Object Oriented so they want
“main” method of the class to be present inside of the class only and still execute without the need of class object
and to do that they have divided members of a class into 2 categories, like:
• Non-static Members
• Static Members
Every member of a class is by default a non-static member only and what we have learnt till now in C or
CPP Language is also about non-static members only, whereas if we prefix any of those members with static keyword,
we call them as Static Members.
class Test
{
int x = 100; //Non-Static Member
static int y = 200; //Static Member
}
Note: Static members of the class doesn't require object of that class for both initialization and execution also,
whereas non-static members require it, so in Java Language "main method" is defined inside of the class only but
declared as static, so even if it is inside of the class also it can start the execution without the need of class object.

Object Oriented Programming in C#: C# Language came into existence after Java and was influenced by Java, so in
C# Language also the programming style will be same as Java i.e. defining Main method inside the class by declaring
it as "static".

Note: In Java or C# Languages if at all the class contains only Main method in it we don't require to create object or
instance of that class to run the class.

18
Writing programs by using CSharp Language: CSharp language has lot of standards to be followed while writing
code, as following:
1. It's a case sensitive language so we need to follow the below rules and conventions:
I. All keywords in the language must be in lower case (rule).
II. While consuming the libraries, names will be in Pascal case (rule). E.g.: WriteLine, ReadLine
III. While defining our own classes and members to name them we can follow any casing pattern but Pascal
case is suggested (convention).
2. A CSharp program should be saved with “.cs” extension.
3. We can use any name as a file name under which we write the program but class name is suggested to be
used as file name also.
4. To write programs in C# we use an IDE (Integrated Development Environment) known as Visual Studio.Net
but we can also write them by using any text editor like Notepad also.
Syntax to define a class:
[<modifiers>] class <Name>
{
-Define Members here [] => Optional
} <> => Any
• modifiers are some special keywords that can be used on a class like public, internal, static, abstract, partial,
sealed, etc.
• class is a keyword to tell that we are defining a class just like we used struct keyword to define a structure
in C Language.
• <Name> refers to name of the class for identification.
• Members refer to contents of the class like fields, methods, etc.
Syntax to define Main Method in the class:
static void Main( [string[] args] )
{
-Stmt's
}
• static is a keyword we use to declare a member as static member and if a member is declared as static,
instance of the class is not required to call or execute it. In C# Main method should be declared static to
start the execution from there.
• void is a keyword to specify that, Main method is non-value returning.
• Main is name of the method, which can't be changed and more over it should be in Pascal Case.
• If required (optional) we can pass parameters to Main method but it should be of type string array only.
• Stmt's refers to the logic we want to implement.
Writing the first program in CSharp using Notepad:

Step 1: Open Notepad and write the following code in it:


class First
{
static void Main()
{
System.Console.WriteLine("My first C# program.");
}
}

19
Step 2: Saving the program.
Create a folder on any drive of your computer with the name “CSharp” and save the above file into that folder
naming it as “First.cs”.

Step 3: Compilation of the program.


We need to compile our C# program by using C# Compiler at “Developer Command Prompt”, provided along with
the Visual Studio software, and to do that go to Windows Search and search for "Developer Command Prompt for
VS", click on it to open. Once it is open it will be pointing to the location where Visual Studio software is installed, so
change to the location where you have created the folder and compile the program as following:

Syntax: csc <File Name>


E.g.: <drive>:\CSharp> csc First.cs ⏎
Once the program is compiled successfully it generates an output file with the name First.exe that contains “CIL
(Common Intermediate Language) or MSIL (Microsoft Intermediate Language) Code” in it which we need to execute.

Step 4: Execution of the program.


Now at the same Command Prompt we can run our First.exe file as below:
E.g.: <drive>:\CSharp> First ⏎
System.Console.WriteLine:
Console is a pre-defined class under the Libraries of our language which provides with a set of static
members using which we can perform IO operations on the standard IO devices. WriteLine is a method in the class
Console to display output on the monitor, and apart from WriteLine method there are many other methods present
in the class Console like: Write, Read, ReadLine, ReadKey, Clear, etc and all these methods are also static, so we can
call them directly by prefixing the class name.

System is a namespace and a namespace is a logical container for types like: Class, Structure, Interface,
Enum and Delegate, and we use these namespaces in a language for 2 reasons:

1. Grouping related types i.e. types that are designed for developing similar kind of App's are grouped together
under a namespace for easy access and identification as following:

2. To overcome the naming collision i.e. if a project contains multiple types with the same name we can
overcome conflict between names by putting them under separate namespaces, as following:

Note: Every pre-defined type in our Libraries is defined under some namespace and we can also define types under
namespaces and we will learn this process while working with Visual Studio IDE.

20
If a type is defined under any namespace then, when ever and where ever we want to consume the type
we need to prefix namespace name to type name and this is the reason why in our previous program we have
referred to “Console” class as “System.Console”. To overcome the problem of prefixing namespace name every time
before the type, we are provided with an option of “importing a namespace” which is done by “using directive” as
following:
Syntax: using <namespace>;
using System;
using Microsoft.VisualBasic;
Note: We can import any no. of namespaces as above but each import should be a separate statement.

What is a directive?
Ans: directive in our language is an instruction that is given to the compiler which it has to follow, by importing the
namespace we are telling the C# compiler that types consumed in the program are from the imported namespace.

To test the process of importing a namespace write the below code in Notepad and execute:

using System;
class Second
{
static void Main()
{
Console.Clear();
Console.WriteLine("Importing a namespace.");
}
}

Note: If there are multiple namespaces containing a type with same name then it's not possible to consume those
types by importing the namespace, and in such cases it's mandatory to refer to each type by prefixing the namespace
name to them as following:
E.g.: NSP1.First NSP2.First
using static directive:
This is a new feature introduced in “C# 6.0” which allows us to import a type and then consume all the static
members of that type without a type name prefix.
Syntax: using static <namespace.type>;
using static System.Console;

To test the process of importing a class write below code in Notepad and execute:

using static System.Console;


class Third
{
static void Main()
{
Clear(); WriteLine("Importing a type.");
}
}

21
Data Types in C#

C# Types IL Types Size/Capacity Default Value


Integer Types
byte System.Byte 1 byte (0 - 255) 0
short System.Int16 2 bytes (-2 ^ 15 to 2 ^ 15 - 1) 0
int System.Int32 4 bytes (-2 ^ 31 to 2 ^ 31 - 1) 0
long System.Int64 8 bytes (-2 ^ 63 to 2 ^ 63 - 1) 0
sbyte System.SByte 1 byte (-128 to 127) 0
ushort System.UInt16 2 bytes (0 to 2 ^ 16 - 1) 0
uint System.UInt32 4 bytes (0 to 2 ^ 32 - 1) 0
ulong System.UInt64 8 bytes (0 to 2 ^ 64 - 1) 0
Decimal Types
float System.Single 4 bytes 0
double System.Double 8 bytes 0
decimal System.Decimal 16 bytes 0
Boolean Type
bool System.Boolean 1 byte false
DateTime Type
DateTime System.DateTime 8 bytes 01/01/0001 00:00:00
Unique Identifier Type
Guid System.Guid 32 bytes 00000000-0000-0000-
000000000000
Character Types
char System.Char 2 bytes \0
string System.String null
Base Type
object System.Object null

• All the above types are known as primitive/pre-defined types i.e. they are defined under the libraries of our
language which can be consumed from anywhere.

• All C# Types after compilation of source code gets converted into IL Types and in IL Format these types are
either classes or structures defined under the "System" namespace. String and Object types are classes,
whereas rest of the other 15 types, are structures.

• short, int, long & sbyte types can store signed integer (Positive or Negative) values where as ushort, uint,
ulong & byte types can store un-signed integer (Pure Positive) values only.

• Guid is a type used for storing Unique Identifier values that are loaded from SQL Server DB, which is a 32
byte alpha-numeric string holding a Global Unique Identifier value and it will be in the following format:
00000000-0000-0000-0000-000000000000.

22
• The size of char type has been increased to 2 bytes for giving support to Unicode characters i.e. characters
of languages other than English.
• We are aware that every English language character has a numeric value representation known as ASCII;
characters of languages other than English also have that numeric value representation and we call it as
Unicode.
char ch = 'A'; => ASCII => Binary
char ch = 'अ'; => Unicode => Binary

• Just like ASCII values converts into binary for storing by a computer; Unicode values also converts into
binary, but the difference is ASCII requires 1 byte of memory for storing its value whereas Unicode requires
2 bytes of memory for storing its value.

• String is a variable length type i.e. it doesn't have any fixed size and its size varies based on the value that
is assigned to it.

• Object is a parent of all the types, so capable of storing any type of value in it and more over it is also a
variable length type.
Syntax to declare fields and variables in a class:
[<modifiers>] [const] [readonly] <type> <name> [=default value] [,...n]

class Test
{
int x; //Field (Global Scope)
static void Main()
{
int x = 100; //Variable (Local Scope)
}
}

• "<type>" refers to the type of field or variable we want to declare and it can be any of the 17 types we
discussed above.
• "<name>" refers to the name of the field or variable and it should be unique within the location.
E.g.: int i; float f; bool b; char c; string s; object o; DateTime dt; Guid id;
• Fields and variables can be initialized with any value at the time of their declaration and if they are not
initialized then every field has a default value which is "0" for all numeric types, "false" for bool type, "\0"
for char type, "00000000-0000-0000-0000-000000000000" for Guid type, "01/01/0001 00:00:00" for
DateTime type and "null" for string and object types.

Note: Variables doesn't have any default value so it's must to initialize them while declaration or before
consumption. E.g.: int x = 100;

• Modifiers are generally used to define the scope of a field i.e. from where it can be accessed, and the default
scope for every member of a class in our language is private which can be either changed to public or
internal or protected.

23
• "const" is a keyword to declare a constant and those constants values can't be modified once after their
declaration:
const float pi = 3.14f; //Declaration and Initialization
• "readonly" is a keyword to declare a field as readonly and these readonly field values also can't be modified,
but after initialization:
readonly float pi; //Declaration
pi = 3.14f; //Initialization

Note: decimal values are by default treated as double by the compiler, so if we want to use them as float the value
should be suffixed with character "f" and "m" to use the value as decimal.
float pi = 3.14f; double pi = 3.14; decimal pi = 3.14m
using System;
class TypesDemo {
static int x; //Field
static void Main() {
Console.Clear();
Console.WriteLine("Field x value is: " + x + " and it's type is: " + x.GetType());
int y = 20; //Variable
Console.WriteLine("Variable y value is: " + y + " and it's type is: " + y.GetType());
float f = 3.14f; //Variable
Console.WriteLine("Variable f value is: " + f + " and it's type is: " + f.GetType());
double d = 3.14; //Variable
Console.WriteLine("Variable d value is: " + d + " and it's type is: " + d.GetType());
decimal de = 3.14m; //Variable
Console.WriteLine("Variable de value is: " + de + " and it's type is: " + de.GetType());
}
}

Note: GetType() is a pre-defined method which returns the type of a variable or field or instance on which it is called.
Data Types are divided into 2 categories:
1. Value Types 2. Reference Types

Value Types:
• All fixed length types comes under the category of value types. E.g.: integer types, decimal types, bool type,
char type, DateTime type and Guid type.

• Value types will store their values on "Stack" and stack is a Data Structure that works on a principal “First
in Last out (FILO)” or “Last in First out (LIFO)”.

• Each and every program when it starts the execution, a Stack will be created and given to that program for
storing its values and in the end of program's execution Stack is destroyed.

• Every program will be having its own stack for storing values that are associated with the program and no
2 programs can share the same stack.

24
• Stack is under the control of O.S. and memory allocation is performed only in fixed length i.e. once allocated
that is final which can't either be increased or decreased also.
Reference Types:
• All variable length types comes under the category of reference types and these types will store their values
on "Heap" memory and their address or reference is stored on Stack. E.g.: String and Object.

• Heap memory doesn't have any limitations like stack and it provides a beautiful feature like, Dynamic
Memory Management and because of that, all programs in execution can share the same heap.

• In older programming languages like C and CPP, Heap Memory is under developer's control, whereas in
modern programming languages like Java and .NET, Heap memory is under control of special component
known as "Garbage Collector", so we call Heap memory in these languages as "Managed Heap".

Suppose if we declare fields in a program as following:


int i = 100; char ch = 'A'; double d = 45.83; string s = "Hello";

Then memory is allocated for them as following:

Nullable Value Types: These are introduced in C# 2.0 for storing null values under value types because, by default
value types can't store null values under them where as reference types can store null values under them.
string str = null; //Valid
object obj = null; //Valid
int i = null; //Invalid
decimal d = null; //Invalid

To overcome the above problem nullable value types came into picture and if we want a value type as
nullable we need to suffix the type with "?" and declare it as following:
int? i = null; //Valid
decimal? d = null; //Valid
Implicitly typed variables: This is a new feature introduced in C# 3.0, which allows declaring variables by using "var"
keyword, so that the "type" of that variable is identified based on the value that is assigned to it, for example:
var i = 100; //i is of type int
var f = 3.14f; //f is of type float
var b = true; //b is of type bool
var s = "Hello"; //s is of type string

Note: While using implicitly typed variables we have 2 restrictions:


1. We can't declare these variables with-out initialization. E.g.: var x; //Invalid
2. We can use "var" only on variables but not on fields.

25
Dynamic Type: This is a new type introduced in C# 4.0, which is very similar to implicitly typed variables we discussed
above, but here in place of "var" keyword we use dynamic.
Differences between "var" and "dynamic"

var dynamic
Type identification is performed at compilation time. Type identification is performed at runtime.
Once the type is identified can't be changed to a new We can change the type of dynamic with a new value in
type again. every statement.
var v = 100; //v is of type int dynamic d = 100; //d is of type int
v = 34.56; //Invalid d = 34.56; //d is of type double (Valid)
Can't be declared with-out initialization. Declaration time initialization is only optional.
var v; //Invalid dynamic d; //Valid
d = 100; //d is of type int
d = false; //d is of type bool
d = "Hello"; //d is of type string
d = 34.56; //d is of type double
Can be used for declaring variables only. Can be used for declaring variables and fields also.

using System;
class VarDynamic
{
static void Main()
{
var i = 100;
Console.WriteLine(i.GetType());
var c = 'A';
Console.WriteLine(c.GetType());
var f = 45.67f;
Console.WriteLine(f.GetType());
var b = true;
Console.WriteLine(b.GetType());
var s = "Hello";
Console.WriteLine(s.GetType());
Console.WriteLine("----------------------------------------------------------------------------------------------------------");

dynamic d;
d = 100;
Console.WriteLine(d.GetType());
d = 'Z';
Console.WriteLine(d.GetType());
d = 34.56;
Console.WriteLine(d.GetType());
d = false;
Console.WriteLine(d.GetType());
d = "Hello";
Console.WriteLine(d.GetType());

26
}
}
Boxing and Un-Boxing:
Boxing is a process of converting values types into reference types:
int i = 100;
object obj = i; //Boxing

Unboxing is a process of converting a reference type which is created from a value type back into value type, but
un-boxing requires an explicit conversion:
int j = Convert.ToInt32(obj); //Un-Boxing

Value Type => Reference Type //Boxing


Value Type => Reference Type => Value Type //UnBoxing
Reference Type => Value Type //Invalid

Note: “Convert” is a predefined class in “System” namespace and “ToInt32” is a static method under that class, and
this class also provides other methods for conversion like “ToDouble”, “ToSingle”, “ToDecimal”, “ToBoolean”, etc,
to convert into different types.
Taking input from end user’s into a program:
using System;
class AddNums {
static void Main() {
Console.Clear();

Console.Write("Enter 1st number: ");


string s1 = Console.ReadLine();
double d1 = Convert.ToDouble(s1);

Console.Write("Enter 2nd number: ");


string s2 = Console.ReadLine();
double d2 = double.Parse(s2);

double d3 = d1 + d2;

Console.WriteLine("Sum of " + d1 + " & " + d2 + " is: " + d3);


Console.WriteLine("Sum of {0} & {1} is: {2}", d1, d2, d3);
Console.WriteLine($"Sum of {d1} & {d2} is: {d3}");
}
}

ReadLine method of the Console class is used for reading the input from end user’s into our programs and this
method will perform 3 actions when used in the program, those are:
1. Waits at the command prompt for the user to enter a value.
2. Once the user finishes entering his value, immediately the value will be read into the program.
3. Returns the value as string by performing boxing because return type of the method is string.
public static string ReadLine()

27
Note: after reading the value as string in our program we need to convert it back into it’s original type by performing
an un-boxing which can be done in either of the ways:
string s1 = Console.ReadLine(); string s2 = Console.ReadLine();
double d1 = Convert.ToDouble(s1); double d2 = double.Parse(s2);
or or
double d1 = Convert.ToDouble(Console.ReadLine()); double d2 = double.Parse(Console.ReadLine());

Parse(String): this method is used to convert the string representation of a value to its equivalent type on which the
method is called.
string s1 = "100" ; int i = int.Parse(s1);
string s2 = "34.56"; double d = double.Parse(s2);
string s3 = "true"; bool b = bool.Parse(s3);
String Interpolation: String interpolation provides a more readable and convenient syntax to create formatted
strings than a string composite formatting feature. An interpolated string is a string literal that might contain
interpolation expressions. When an interpolated string is resolved to a result string, items with interpolation
expressions are replaced by the string representations of the expression results. This feature is available starting
with C# 6.0.
Operators in C#: An operator is a special symbol that tells the compiler to perform a specific mathematical or logical
operation when used between a set of operands. C# has a rich set of built-in operators as following:

Arithmetic Operators => +, -, *, /, %


Assignment Operators => =, +=, -=, *=, /=, %=
Relational Operators => ==, !=, <, <=, >, >=
Logical Operators => &&, ||, !
Unary Operators => ++, --
Miscellaneous Operators => sizeof(), typeof(), is, as, ?:, ??,
using System;
class OperatorsDemo {
static void Main() {
Console.WriteLine(sizeof(double));
//Console.WriteLine(sizeof(string)); //Invalid

Console.WriteLine(typeof(double));

double d = 34.56;
if(d is double)
Console.WriteLine("Hello World");
else
Console.WriteLine("Hello How Are You");

object obj = "Hello";


string str = obj as string;
Console.WriteLine(str);

int x = 100;

28
Console.WriteLine(x == 100 ? "India" : "America");
Console.WriteLine(x == 200 ? "India" : "America");
int? a = 50;
Console.WriteLine(a ?? 100);

int? b = null;
Console.WriteLine(b ?? 100);
}
}
Conditional Statements in C#: It’s a block of code that executes based on a conditional and they are divided into 2
categories.
1. Conditional Branching
2. Conditional Looping

Conditional Branching: These statements allows us to branch the code depending on whether certain conditions are
met or not. C# has 2 constructs for branching code, the “if” statement which allow us to test whether a specific
condition is met or not, and the switch statement which allows us to compare an expression with a number of
different values.

Syntax of “if” Condition:


if (<condition>)
[{] <statements>; [}]
else if (<condition>)
[{] <statements>; [}]
[<multiple else if’s>]
else
[{] <statements>; [}]

Note: Curly braces are optional if the conditional block contains single statement in it or else it’s mandatory.

using System;
class IfDemo
{
static void Main()
{
Console.Write("Enter 1st number: ");
double d1 = double.Parse(Console.ReadLine());
Console.Write("Enter 2nd number: ");
double d2 = double.Parse(Console.ReadLine());

if(d1 > d2)


Console.WriteLine("1st number is greater than 2nd number.");
else if(d1 < d2)
Console.WriteLine("2nd number is greater than 1st number.");
else
Console.WriteLine("Both the given numbers are equal.");

29
}
}
Syntax of “switch case” Condition:
switch (<expression>)
{
case <value>:
<stmts>;
break;
[<multiple case blocks>]
default:
<stmts>;
break;
}

Note: In C and CPP languages using a break statement after each “case block” is only optional whereas it is
mandatory in case of C# language, which should be used after default block also.

using System;
class SwitchDemo {
static void Main() {
Console.Write("Enter Student No. (1-3): ");
int Sno = int.Parse(Console.ReadLine());

switch(Sno)
{
case 1:
Console.WriteLine("Student 1");
break;
case 2:
Console.WriteLine("Student 2");
break;
case 3:
Console.WriteLine("Student 3");
break;
default:
Console.WriteLine("No student exists with given number.");
break;
}
}
}
Conditional Looping: C# provides 4 different loops that allow us to execute a block of code repeatedly until a certain
condition is met and those are:
1. for loop 2. while loop 3. do..while loop 4. foreach loop

Every loop requires 3 things in common:


1. Initialization: This set’s the start point for a loop.

30
2. Condition: This decides when the loop has to end.
3. Iteration: This takes the loop to the next level either in forward or backward direction.
Syntax of “for loop”:
for (initializer;condition;iteration) {
-<statements>;
}
Example:
for(int i = 1;i <= 100;i++)
{
Console.WriteLine(i);
}
Syntax of “while loop”:
while (<condition>) {
-<statements>;
}
Example:
int i = 1;
while(i <= 100) {
Console.WriteLine(i);
i++;
}
Syntax of “do..while loop”:
do {
-<statements>;
}
while (<condition>);
Example:
int i = 1;
do {
Console.WriteLine(i);
i++;
}
while (i <= 100);

Note: the minimum no. of executions in case of a “for loop” and “while loop” are “0” because in both these cases
the loop starts its execution only when the given condition is satisfied whereas the minimum no. of executions in
case of a “do...while loop” is “1” because in this case after executing the loop for first time, then only it will check
for the condition to continue the loop’s execution.
Syntax of “foreach loop”:
foreach(type var_name in array_name|collection_name)
{
-<statements>;
}
Note: foreach loop is specially designed for accessing values from an array or collection.

31
Jump Statements: these are statements which will transfer the control from 1 line of execution to another line. C#
has no. of statements that allows jumping to another line in a program, those are:
1. goto 2. break 3. continue 4. return
goto: it allows us to jump directly to another specified line in the program, indicated by a label which is an identifier
followed by a colon.
goto xxx:
Console.WriteLine(“Hello World”);
xxx:
Console.WriteLine(“Goto Called.”);
break: it is used to exit from a case in a switch statement and also used to exit from any conditional loop statement
which will switch the control to the statement immediately after end of the loop.
for (int i = 1;i <= 100;i++) {
Console.WriteLine(i);
if (i == 50)
break;
}
Console.WriteLine(“End of the loop.”);
continue: it is used only in a loop which will jump the control to iteration part of the loop without executing any
other statement that is present next to it.
for (int i = 1;i <= 100;i++)
{
if (i == 7 || i = 77)
continue;
Console.WriteLine(i);
}
return: this is used to terminate the execution of a method in which it is used and jumps out of that method, while
jumping out it can also carry a value out of that method which was only optional.

using System;
class Table
{
static void Main()
{
Console.Write("Enter a number: ");
bool Status = uint.TryParse(Console.ReadLine(), out uint x);
if(Status == true)
{
if(x == 0)
return;
Console.Clear();
for(uint i=1;i<=10;i++)
{
Console.WriteLine("{0} * {1} = {2}", x, i, x * i);
}
}
else

32
Console.WriteLine("Please enter un-signed integer value as input.");
} //End of the method
} //End of the class
Array: it is a set of similar type values that are stored in a sequential order either in the form of a row or rows &
columns. In C# language also we access the values of an array by using the index only which will start from “0” and
ends at the “no. of items - 1”. In C# arrays can be declared either as fixed length or dynamic, where a fixed length
array can store a pre-defined no. of items whereas the size of a dynamic array increases as we add new items to it.

1-Dimensional Array’s: these arrays will store data in the form of a row and are declared as following:

Syntax: <type>[] <array_name> = new <type>[length|size]

Example:
int[] arr = new int[5]; //Declaration and Initialization with default values
or
int[] arr; //Declaration
arr = new int[5]; //Initialization with default values
or
int[] arr = { <list of values> }; //Declaration and Initialization with given set of values

using System;
class SDArray1 {
static void Main() {
Console.Clear();
int x = 0;
int[] arr = new int[6];

//Accessing values of a SD Array by using for loop


for(int i=0;i<6;i++)
Console.Write(arr[i] + " ");
Console.WriteLine();

//Assigning values to a SD Array by using for loop


for(int i=0;i<6;i++)
{
x += 10;
arr[i] = x;
}

//Accessing values of a SD Array by using foreach loop


foreach(int i in arr)
Console.Write(i + " ");
Console.WriteLine();
}
}

33
foreach loop: this loop is specially designed for accessing values from an array or a collection. When we use foreach
loop for accessing values, the loop starts providing access to values of the array or collection by assigning the values
to loop variable in a sequential order as following:

Differences between for loop and foreach loop in accessing values of an array or collection:
1. In case of a “for loop”, the loop variable refers to index of the array whereas in case of a “foreach loop”,
the loop variable refers to values of the array.
2. By using a “for loop” we can either access or assign values to an array whereas by using a “foreach loop”
we can only access the values from an array.
3. In case of a “for loop”, the data type of loop variable is always int only irrespective of the type of values in
the array, whereas in case of a “foreach loop”, the data type of loop variable will be same as the type of
values in the array.

int[] iarr = { 10, 20, 30, 40, 50 };


double[] darr = { 12.34, 34.56, 56.78, 78.90, 90.12 };
string[] sarr = { "Red", "Blue", "Green", "Yellow", "Magenta" };

for (int i=0;i<iarr.Length;i++) foreach(int i in iarr)


for (int i=0;i<darr.Length;i++) foreach(double d in darr)
for (int i=0;i<sarr.Length;i++) foreach(string s in sarr)

Array Class: this is a pre-defined class under the System namespace which provides with a set of members in it to
perform actions on an array, those are:
Sort(Array arr) => void //Method
Reverse(Array arr) => void //Method
Copy(Array src, Array dest, int n) => void //Method
GetLength(int dimension) => int //Method
Length => int //Property (Field)

using System;
class SDArray2 {
static void Main() {
Console.Clear();
int[] arr = { 54, 79, 59, 8, 42, 22, 93, 3, 73, 38, 67, 48, 18, 61, 32, 86, 15, 27, 81, 96 };

for(int i=0;i<arr.Length;i++)
Console.Write(arr[i] + " ");
Console.WriteLine();

Array.Sort(arr);

34
foreach(int i in arr)
Console.Write(i + " ");
Console.WriteLine();
Array.Reverse(arr);
foreach(int i in arr)
Console.Write(i + " ");
Console.WriteLine();

int[] brr = new int[10];


Array.Copy(arr, brr, 7);
foreach(int i in brr)
Console.Write(i + " ");
Console.WriteLine();
}
}
2-Dimensional Array’s: these arrays will store data in the form of rows & columns, and are declared as following:
Syntax: <type>[,] <array_name> = new <type>[rows, columns]
Example:
int[,] arr = new int[4,5]; //Declaration and Initialization with default values
or
int[,] arr; //Declaration
arr = new int[4,5]; //Initialization with default values
or
int[,] arr = { <list of values> }; //Declaration and Initialization with given set of values

using System;
class TDArray {
static void Main() {
int x = 0; int[,] arr = new int[4, 5];
//Accessing values of TD Array by using foreach loop
foreach(int i in arr)
Console.Write(i + " ");
Console.WriteLine();

//Assigning values to TD Array by using nested for loop


for(int i=0;i<arr.GetLength(0);i++) {
for(int j=0;j<arr.GetLength(1);j++) {
x += 5; arr[i,j] = x;
}
}

//Accessing values of TD Array by using nested for loop


for(int i=0;i<arr.GetLength(0);i++) {
for(int j=0;j<arr.GetLength(1);j++)
Console.Write(arr[i,j] + " ");
Console.WriteLine();

35
}
}
}
Assigning values to 2-D Array at the time of its declaration:
int[,] arr = {
{ 11, 12, 13, 14, 15 },
{ 21, 22, 23, 24, 25 },
{ 31, 32, 33, 34, 35 },
{ 41, 42, 43, 44, 45 }
};
Jagged Arrays: these are also 2-Dimensional arrays only which will store the data in the form of rows and columns
but the difference is in-case of a 2-Dimensional array all the rows will be having equal no. of columns whereas in
case of a jagged array the column size varies from row to row. Jagged arrays are also known as “array of array”
because here each row is considered as a single dimensional array and multiple single dimensional arrays with
different sizes are combined together to form a new array.
Syntax: <type>[][] <array_name> = new <type>[rows][]
Example:
int[][] arr = new int[4][]; //Declaration
or
int[][] arr = { <list of values> }; //Declaration & Initialization with given set of values

Note: in case of a jagged array we can’t initialize the array with default values at the time of its declaration i.e. first
we need to specify the no. of rows and then pointing to each row we need to specify the no. of columns to that row,
as following:
int[][] arr = new int[4][]; //Declaration
arr[0] = new int[5]; //Initialization of 1st row
arr[1] = new int[6]; //Initialization of 2nd row
arr[2] = new int[8]; //Initialization of 3rd row
arr[3] = new int[4]; //Initialization of 4th row

Internally the memory is allocated for the array as following:

using System;
class JArrayDemo {
static void Main() {
Console.Clear();

int[][] arr = new int[4][];


arr[0] = new int[5];

36
arr[1] = new int[6];
arr[2] = new int[8];
arr[3] = new int[4];
//Accessing values of Jagged Array by using nested foreach loop
foreach(int[] iarr in arr) {
foreach(int x in iarr)
Console.Write(x + " ");
Console.WriteLine();
}
Console.WriteLine("--------------------------------------");

//Accessing values of Jagged Array by using for loop in foreach loop


foreach(int[] iarr in arr) {
for(int i=0;i<iarr.Length;i++)
Console.Write(iarr[i] + " ");
Console.WriteLine();
}
Console.WriteLine("--------------------------------------");

//Assigning values to Jagged Array by using for loop in foreach loop


foreach(int[] iarr in arr) {
for(int i=0;i<iarr.Length;i++) {
iarr[i] = i + 1;
}
}

//Accessing values of Jagged Array by using nested for loop


for(int i=0;i<arr.GetLength(0);i++) {
for(int j=0;j<arr[i].Length;j++)
Console.Write(arr[i][j] + " ");
Console.WriteLine();
}
Console.WriteLine("--------------------------------------");

//Assigning values to Jagged Array by using nested for loop


for(int i=0;i<arr.GetLength(0);i++) {
for(int j=0;j<arr[i].Length;j++) {
arr[i][j] = i + 1;
}
}

//Accessing values of Jagged Array by using foreach loop in for loop


for(int i=0;i<arr.GetLength(0);i++) {
foreach(int x in arr[i])
Console.Write(x + " ");
Console.WriteLine();

37
}
}
}
Assigning values to Jagged Array at the time of its declaration:
int[][] arr = {
new int[5] { 11, 12, 13, 14, 15 },
new int[6] { 21, 22, 23, 24, 25, 26 },
new int[8] { 31, 32, 33, 34, 35, 36, 37, 38 },
new int[4] { 41, 42, 43, 44 },
};
Implicitly typed arrays: Just like we can declare variables by using “var” keyword we can also declare arrays by using
the same “var” keyword and here also the type identification is performed based on the values that are assigned to
the array.

var iarr = new[] { 10, 20, 30, 40, 50 }; //Implicitly type integer array
var sarr = new[] { "Red", "Blue", "Green", "Yellow", "Magenta" }; //Implicitly typed string array
var darr = new[] { 12.34, 34.56, 56.78, 78.90 90.12 }; //Implicitly typed double array
var jarr = new[] {
new[] { 11, 12, 13, 14, 15 },
new[] { 21, 22, 23, 24, 25, 26 },
new[] { 31, 32, 33, 34, 35, 36, 37, 38 },
new[] { 41, 42, 43, 44 }
new[] { 51, 52, 53, 54, 55, 56, 57 }
}; //Implicitly typed jagged integer array
Command Line Arguments: Arguments which are passed by the user or programmer to the Main method are known
as Command-Line Arguments. Main method is the entry point for the execution of a program and this Main method
can accepts an array of strings.

using System;
class Params {
static void Main(string[] args) {
foreach(string str in args)
Console.WriteLine(str);
}
}

After compilation of the program execute the program at Command Prompt as following:
<drive>:\CSharp> Params 100 Hello 34.56 A true ⏎

Note: We can pass any no. of values as well as any type of values as Command Line Arguments to the program, but
each value should be separated with a space and all those values we passed will be captured in the string array (args)
of main method. In the above case (100, Hello, 34.56, A, true) are 5 values we have supplied to the Main method of
Params class.

Adding a given set of numbers that are passed as Command Line Arguments:
using System;

38
class AddParams {
static void Main(string[] args) {
double Sum = 0;
foreach(string str in args)
Sum = Sum + double.Parse(str);
Console.WriteLine("Sum of given {0} no's is: {1}", args.Length, Sum);
}
}

After compilation of the program execute the program at Command Prompt as following:
<drive>:\CSharp> AddParams 10 20 30 ⏎
<drive>:\CSharp> AddParams 34.56 28.93 98.45 63.28 ⏎
<drive>:\CSharp> AddParams 938.387 534 348.378 836 174.392 ⏎
<drive>:\CSharp> AddParams 18 48.37 75 56.43 97 85.19 ⏎

Working with Visual Studio.Net


Visual Studio is an IDE (Integrated Development Environment) used for developing .Net Applications by
using any .Net Language like CSharp, VB etc., as well as we can develop any kind of applications like Console,
Windows and Web etc.

Note: the current version of Visual Studio is 16 which come as Visual Studio 2019.

To open Visual Studio, go to Windows Search and search for Visual Studio 2019 and click on it to open,
which will launch as following:

Applications that are developed under VS are known as projects, where each project is a collection of items
like Class, Interface, Structure, Enum, Delegate, Html Files, XML Files, and Text Files etc. To create a Project click on
"Create a new project" option in the above Page which opens a new window as following:

39
In the above window under "All languages" DropDownList select "C#", under "All platforms" DropDownList
select "Windows" and under "All project_types" DropDownList select "Console" which will display the options as
following:

Now select "Console App (.Net Core)" in the above window and click “Next” button which opens a new
window as following:

In that above window under ProjectName TextBox enter the name of project as "FirstProject", under
Location TextBox enter or select our personal folder location i.e. "<drive>:\CSharp" and click on "Create" button:

This action will create a new project with a default class Program under a file “Program.cs” which will be as
following:

using System;
namespace FirstProject
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}

40
When types are defined in Visual Studio by default all those types will be under a namespace whose name
will be same as project name i.e. “FirstProject” in our case and from now each and every type of the project will be
defined with-in this namespace only. We have already learnt earlier, that a namespace is a logical container of types
like class, structure, interface, enum and delegate.
To run the class either hit Ctrl + F5 or go to “Debug” menu and select the option “Start Without Debugging”
which will save, compile and executes the program by displaying output “Hello World!” on the console window
because we have opened a “Console App.” Project. To close that console window it will display a message “Press
any key to continue . . .”, so once we hit any key it will close the window and takes us back to the studio. We can
also run the class by hitting F5 or clicking on the button in the ToolBar or go to “Debug” menu and
select the option “Start Debugging”, but in this case it save compile and executes the program but we can’t we the
output because the console window gets closed immediately and in this case to view the output we need to hold
console window and to do that use “Console.ReadLine();” method after “Console.WriteLine("Hello World!");” in
Main method of the program.
Adding new items in the project:
Under VS we find a window in the RHS known as Solution Explorer used for organizing the complete
application, which allows us to view, add and delete items under the projects, if it is not visible in the RHS then go
to “View” menu and select “Solution Explorer” which will launch on RHS that looks as following:

To add new classes under project, open Solution Explorer, right click on the project, select Add => choose
“New Item” option, which opens the "Add New Item" window as following:

In this window select "Class" template, specify a name to it in the bottom or leave the existing name and
click on Add button, which adds the class under project with the name “Class1.cs”. The new class added, also comes
under the Namespace, i.e. “FirstProject”. Now write the below code in the class Class1:

static void Main() {


Console.WriteLine("Second class under the project.");
Console.ReadLine();
}
Now when we run the project we get an error stating that there are multiple entry points in the project
because the 2 classes in the project contains a Main method and each Main method is an entry point, To resolve the
above problem, open Solution Explorer, right click on the project, select properties, which opens project property
window, under it we find an option "Startup Object" which lists all the classes of project that contains a valid Main

41
method in them, choose your class i.e. “FirstProject.Class1” and run. If the “Startup Object” doesn’t list your class,
again open Solution Explorer, right click on the project, select the option “Edit Project File” which opens an “XML
File” and in that we find “<StartupObject></StartupObject>” tags with the existing Startup class name listed, change
that name to your class name: “<StartupObject>FirstProject.Class1</StartupObject>” and run.
Object Oriented Programming
This is an approach that we use in the industry for developing Application, introduced in 70's replacing the
traditional Procedural Programming Approach. Procedural Programming Approach doesn't provide Security and Re-
usability, where as these 2 are the major strength of Object Oriented Programming Approach.

Any language to be called as Object Oriented needs to satisfy 4 important principals that are prescribed
under the standards of Object Oriented Programming and they are:
1. Encapsulation => hiding the data
2. Abstraction => hiding the complexity
3. Inheritance => re-usability
4. Polymorphism => behaving in different ways based on input received

Encapsulation: this is all about hiding of data or members of a program by wrapping them under a container known
as a Class, which provides security for all its contents.

Abstraction: this is all about hiding the complexity of code and then providing with a set of interfaces to consume
those functionalities, for example functions/methods in a program are good example for this, because here we are
only aware of how to call them but we are never aware of the underlying logic behind that implementation.

Inheritance: this provides re-usability i.e. members that are defined in 1 class can be consumed from other classes
by establishing parent/child relation between the classes.

Polymorphism: behaving in different ways based on the input received is known as polymorphism i.e. whenever the
input changes then the output or behavior also changes accordingly.
Class: It's a user-defined type which is in-turn a collection of members like:
• Fields
• Methods
• Constructors
• Destructors or Finalizers

42
• Properties
• Indexers
• Events
• De-constructors (Introduced in C# 7.0)
Method: It is a named block of code which performs an action whenever it is called and after completion of that
action it may or may not return any result of that action, and they are divided into 2 categories:
1. Value returning method (Function)
2. Non-value returning method (Sub-Routine)
Syntax to define a method:
[<modifiers>] void|type <Name>( [<Parameter List>] )
{
-Stmt's or Logic [] => Optional
} <> => Any

Modifiers are some special keywords which can be used on a method if required like public, internal, protected,
static, virtual, abstract, override, sealed, partial, etc.

void|type is to tell whether our method is value returning or non-value returning i.e. void implies that the method
is non-value returning, whereas if we want our method to return any value then we need to specify the type of value
it has to return by using the “type”.

Example for non-value returning method:


public static void Clear()
public static void WriteLine(<type> var)

Example for value returning method:


public static string ReadLine()

Note: the return type of a method need not be any pre-defined type like int, float, char, bool, DateTime, Guid, string,
object, etc, but it can also be any user-defined type also.

<Name> refers to id of the method for identification.

[<Parameter list>]: if required we can pass parameters to our methods for execution, and parameters of a method
will make an action dynamic, for example:
GetLength(0) => Returns rows
GetLength(1) => Returns columns

Syntax to pass parameters to a method:


[ref|out] [params] <type> <var> [=default value] [,...n]
Where should we define methods?
Ans: As per the rule of Encapsulation methods should be defined inside of a class.

How to execute a method that is defined under a class?


Ans: The methods that are defined in a class must be explicitly called for execution, except Main method because
Main is implicitly called.

43
How to call a method that is defined in a class?
Ans: Methods are of 2 types:
1. Non-Static 2. Static
Note: By default every method of a class is non-static only, and if we want to make it as static we need to prefix the
“static” modifier before the method as we are doing in case of Main method.

To call a method that is defined under any class we require to create instance of that class provided the
methods are non static, whereas if the methods are static we can call them directly by using class name, for example
WriteLine and ReadLine are static methods in class Console which we are calling in our code as Console.WriteLine
and Console.ReadLine.

How to create instance of a class?


Ans: We create the instance of class as following:
Syntax: <class_name> <instance_name> = new <class_name> ( [<List of values>] )

Example:
Program p = new Program(); //Declaration and Initialization
or
Program p; //Declaration
p = new Program(); //Initialization

Note: with-out using “new” keyword we can’t create the instance of a class in Java and .NET Languages.

Where should we create the instance of a class?


Ans: instance of a class can be created either with-in the same class or in other classes also.

If instance is created in the same class it should be created under a static block; generally we create
instances in Main method because of 2 reasons:
1. Entry Point of the program.
2. It is a static block.

If instance is created in another class then it can be created in any block of that class i.e. either static or
non-static also.
To try all the above, create a new project in Visual Studio naming it as “OOPSProject” and write the below
code under the default class “Program”:

class Program {
//Non-value returning method without parameters
public void Test1() { //Static in behavior
int x = 5;
for (int i = 1; i <= 10; i++)
Console.WriteLine("{0} * {1} = {2}", x, i, x * i);
}

//Non-value returning method with parameters

44
public void Test2(uint x, uint ub) { //Dynamic in behavior
for (uint i = 1; i <= ub; i++)
Console.WriteLine("{0} * {1} = {2}", x, i, x * i);
}
//Value returning method without parameters
public string Test3() { //Static in behavior
string str = "Hello world";
str = str.ToUpper();
return str;
}

//Value returning method with parameters


public string Test4(string str) { //Dynamic in behavior
str = str.ToUpper();
return str;
}

static void Main(string[] args) {


//Creating the instance of class
Program p = new Program();

//Calling non-value returning methods


p.Test1();
Console.WriteLine();
p.Test2(8, 12);
Console.WriteLine();

//Calling value returning methods


string s1 = p.Test3();
Console.WriteLine(s1);
string s2 = p.Test4("india");
Console.WriteLine(s2);
Console.ReadLine();
}
}
Consuming a class from other classes: It is possible to consume a class and its members from other classes in 2
different ways:
1. Inheritance
2. Creating a instance

To test the second, add a new class in the project naming it as “TestProgram.cs” and write the below code
under class:

class TestProgram {
public void CallMethods() {
Program p = new Program();

45
p.Test1(); p.Test2(9, 15);
Console.WriteLine(p.Test3());
Console.WriteLine(p.Test4("america"));
}
static void Main() {
//Creating an un-named instance and calling the method
new TestProgram().CallMethods();
Console.ReadLine();
}
}
Note: Un-named instances are created and used when we want to call any single member of a class or when we
want to use that instance only for 1 time.
Code files in a project: When we want to add a new class under any project we first open the “Add New Item”
window and in that we choose “Class Item Template”, which when added will add a file with a class template in it,
same as that we also find “Code File Item Template” which when added will add a blank file and we need to write
everything manually in it, just like we write code using Notepad.

Defining multiple classes in a file: It’s possible to define “n” no. of classes under a single “.cs” file, but “Main” method
can be defined under 1 class only. Even if it is not mandatory it is advised to use the “Class Name” under which we
defined “Main” method as the “File Name”.

User-defined return types to a Methods: The return type of a method need not be any pre-defined type, but can
also be any user-defined type also i.e. a type which is defined representing some complex data.
To test all the above, add a “Code File” under the project naming it as “UserDefinedTypes.cs” and write the
below code in it:

using System;
namespace OOPSProject {
class Emp {
public int Eno;
public string Name, Job;
public double Salary;
public bool Status;
}
class UserDefinedTypes {
public Emp GetEmpDetails(int Eno) {
Emp e = new Emp();
e.Eno = Eno;
e.Name = "Ajay";
e.Job = "Salesman";
e.Salary = 6000.00;
e.Status = true;
return e;
}
static void Main() {
UserDefinedTypes udt = new UserDefinedTypes();

46
Emp obj = udt.GetEmpDetails(1008);
Console.WriteLine(obj.Eno + " " + obj.Name + " " + obj.Job + " " + obj.Salary + " " + obj.Status);
Console.ReadLine();
}
}
}

In the above case “Emp” is a new type (User-Defined and Complex) and that type is used as a return type
for our method “GetEmpDetails”.
Parameters of a Method:
We define parameters to methods for making actions dynamic i.e. as discussed earlier every method is an
action and to make those actions dynamic we define parameters to methods.

Syntax for defining parameters to a method:


[ref|out] [params] <type> <parameter_name> [=default value] [,...n]
Parameters of a method are classified as:
1. Input Parameters
2. Output Parameters
3. InOut Parameters

• Input parameters will bring values into the method for execution.
• Output parameters will carry results out of the method after execution.
• InOut Parameters are a combination of above 2 i.e. these parameters will 1st bring a value into the method
for execution and after execution, the same parameter will carry results out of the method.

By default every parameter is an input parameter whereas if we want to declare any parameter as output
we need to prefix “out” keyword and to declare a parameter as InOut we need to prefix “ref” keyword before the
parameter, as following:
public void Test(int a, out int b, ref int c)
To test Output Parameters add a new class in the Project naming it as “OutputParameters.cs” and write the
below code in it:

class OutputParameters {
public void Math1(int a, int b, out int c, out int d) { //Before C# 7.0
c = a + b;
d = a * b;
}
public (int, int) Math2(int a, int b) { //From C# 7.0
int c = a + b;
int d = a * b;
return (c, d);
}
static void Main() {
OutputParameters obj = new OutputParameters();

int Sum1, Product1;

47
obj.Math1(100, 25, out Sum1, out Product1);
Console.WriteLine("Sum of given no's is: " + Sum1);
Console.WriteLine("Product of given no's is: " + Product1);
Console.WriteLine("----------------------------------------------------------------------------------------------------------");
obj.Math1(165, 15, out int Sum2, out int Product2); //From C# 7.0
Console.WriteLine("Sum of given no's is: " + Sum2);
Console.WriteLine("Product of given no's is: " + Product2);
Console.WriteLine("----------------------------------------------------------------------------------------------------------");

var (Sum3, Product3) = obj.Math2(252, 12);


Console.WriteLine("Sum of given no's is: " + Sum3);
Console.WriteLine("Product of given no's is: " + Product3);
Console.WriteLine("----------------------------------------------------------------------------------------------------------");

(int Sum4, int Product4) = obj.Math2(315, 9);


Console.WriteLine("Sum of given no's is: " + Sum4);
Console.WriteLine("Product of given no's is: " + Product4);
Console.WriteLine("----------------------------------------------------------------------------------------------------------");
Console.ReadLine();
}
}
To test InOut parameters add a new class in the Project naming it as “InOutParameters.cs” and write the
below code in it:

class InOutParameters {
public void Factorial(ref uint fact) {
if (fact == 0 || fact == 1) {
fact = 1;
}
else {
uint result = 1;
for(uint i = 2;i <= fact;i++) {
result = result * i;
}
fact = result;
}
}
static void Main() {
InOutParameters p = new InOutParameters();
uint num = 8;
Console.Write($"Factorial of {num} is: ");
p.Factorial(ref num);
Console.WriteLine(num);
Console.ReadLine();
}
}

48
Params KeyWord: By prefixing this keyword before an array parameter of any method we get a chance to call that
method without explicitly creating an array and pass to the method, but we can directly pass a set of values in a
“Comma-Seperated” list.
public void AddParams(params double[] args)
For example WriteLine method of Console class is defined as below:
public static void WriteLine(string format, params object[] args)

So we are able to call that method in our earlier program as following:


Console.WriteLine("{0} * {1} = {2}", x, i, x * i);

Note: while using the “params” keyword we have 2 restrictions:


1. We can use it only on 1 parameter of the method.
2. It can be used only on the last parameter of that method.
Default values to parameters: While defining methods we can assign default values to parameters of that method,
so that those parameters will become “optional” and while calling that method it is not mandatory to pass values to
those parameters. If the method is called without passing a value to those parameters then default value of that
parameter will be used, for example:
public void AddNums(int x, int y = 50, int z = 25)

Note: In the above case x is a mandatory parameter whereas y and z are optional parameters and while defining
methods with mandatory and optional parameters, mandatory parameters should be in the 1 st place of parameter
list, followed by optional parameters in the last.
To test “params” keyword and “default valued parameters” add a new class in the project naming it as
“MethodParameters.cs” and write the below code in it:

class MethodParameters {
public void AddParams(params double[] args) { //Method using params keyword on an array parameter
double Sum = 0;
foreach (double d in args) {
Sum = Sum + d;
}
Console.WriteLine($"Sum of given {args.Length} no's is: {Sum}");
}
//Method with default valued parameters
public void AddNums(int x, int y = 50, int z = 25) {
Console.WriteLine($"Sum of the 3 no's is: { x + y + z}");
}
static void Main() {
MethodParameters obj = new MethodParameters();
//Calling a method which uses array as parameter with params keyword
obj.AddParams();
obj.AddParams(56.19);
obj.AddParams(23.45, 78);
obj.AddParams(45, 67.82, 92);
obj.AddParams(32.91, 87, 56.23, 17);
Console.WriteLine("----------------------------------------------------------------------------------------------------------");

49
//Calling a method which has default valued parameters
obj.AddNums(100);
obj.AddNums(100, 100);
obj.AddNums(100, z: 100);
obj.AddNums(100, 100, 100);
Console.ReadLine();
}
}
Understanding the difference between variable, instance and reference of a class: to understand about a variable,
instance and reference of a class add a new class in our Project naming it as “First.cs” and write below code in it:

class First {
public int x = 100;
static void Main() {
First f; //f is a variable of class
f = new First(); //f is a instance of class
Console.WriteLine(f.x);
Console.ReadLine();
}
}

Every member of a class, if it is non-static can be accessed from the main Method only by using instance of
that class. So in the above case to print the value of “x”, we created instance of class First under Main method.
A variable of class is a copy of class which is not initialized so it doesn't have any memory allocation and
can't be used for calling or accessing the members.
An instance of class is a copy of class which is initialized by using “new” keyword and for an instance memory
is allocated, so by using this instance we can access or call members of that class.

Dereferencing an Instance: it is possible to dereference the instance of any class by assigning “null” to the instance
and once “null” is assigned to instance we can't use that instance for calling members of class and if we try to do so,
we get a runtime error. To test this, re-write the code under “Main Method” of class “First” as below:

First f = new First();


Console.WriteLine(f.x); //Valid
f = null;
Console.WriteLine(f.x); //Invalid (Causes Runtime error)
Console.ReadLine();

Note: once null is assigned to a instance, internally the memory which is allocated for that instance is not de-
allocated immediately, but only gets marked as un-used and all those un-used objects memory will be de-allocated
by “Garbage Collector” whenever it comes into picture.
Creating multiple instances to a class: it is possible to create multiple instances to a class and each instance we
create for the class will be having a separate memory allocation for its members as following:

50
First f1 = new First();
First f2 = new First();

Instances are unique i.e. any modifications that we perform on the members of 1 instance will not reflect
to the members of other instances of the class, and to test this rewrite the code under “Main method” of class First
as below:

First f1 = new First();


First f2 = new First();
Console.WriteLine(f1.x + " " + f2.x);
f1.x = 200;
Console.WriteLine(f1.x + " " + f2.x);
f2.x = 300;
Console.WriteLine(f1.x + " " + f2.x);
Console.ReadLine();

Reference of a class: we can initialize the variable of a class by using any existing instance of that class and we call it
as a reference of the class. References of class will not have any memory allocation like instances, i.e. they will be
consuming the memory of instance using which they are initialized, so a reference is just a pointer to an instance, as
following:

First f1 = new First();


First f2 = f1; //f2 is a reference of class First

Because an instance and reference are accessing the same memory, changes that are performed on the
members by using the instance will reflect when those members are accessed by using reference and vice versa. To
test this, rewrite code under “Main method” of class First as below:

First f1 = new First();


First f2 = f1;
Console.WriteLine(f1.x + " " + f2.x);
f1.x = 200;
Console.WriteLine(f1.x + " " + f2.x);
f2.x = 300;
Console.WriteLine(f1.x + " " + f2.x);
Console.ReadLine();

Note: when an instance and references are accessing the same memory and if “null” is assigned to any 1 of them,
then the 1 to whom null is assigned can't access the memory any more, but still the others can access it as is for
calling the members. To test this re-write code under “Main method” of class First as below:

51
First f1 = new First();
First f2 = f1;
f1 = null;
Console.WriteLine(f2.x); //Valid
Console.WriteLine(f1.x); //Invalid (Causes runtime error)
Console.ReadLine();
Variable of Class: this is a copy of class which is not initialized, so by using this we can't call any members of that
class.

Instance of Class: this is a copy of class which is initialized by using the "new" keyword and by using this we can call
members of that class.

Reference of Class: this is a copy of class which is initialized by using any existing instance of that class and this works
same as an instance. By using the reference also we can call members of that class.
What happens internally when we create the instance of a class?
Ans: When we create the instance of any class internally following actions will take place:
1. Reads the classes to identify their members.
2. Invokes the constructors of all those classes.
3. Allocates the memory that is required for execution.

Constructor
This is a special method present under a class responsible for initializing the data members (fields) of that
class. This method is invoked automatically when we create the instance of class. The name of constructor method
is exactly the same name of the class and more over it's a non-value returning method. Every class requires a
constructor in it, if we want to create the instance of that class or else we can't create the instance of any class.

Note: While defining a class it's the responsibility of developers to define a constructor explicitly under his class, and
if they fails to do so, on-behalf of the developers an implicit constructor gets defined in those classes; so till now we
are creating instances of the classes we defined, by using those implicit constructors only.

For example if we define a class as following:


class Test {
int i = 10; string s; bool b; //Fields
}
After compilation of the above class it will be as following with an implicit constructor:
class Test {
int i = 10; string s; bool b; //Fields
public Test() { //Implicit Constructor
i = 10; s = null; b = false;
}
}
• Implicit constructors are public.
• While declaring a field if we assign any value to it, then constructor will initialize the field with that value
only or else it will initialize the field with default value of that type.
• We can also define our own constructors in our classes and if we do that implicit constructor will not be
defined again.

52
Syntax to define a Constructor Explicitly:
[<modifiers>] <Class Name>( [<Parameter List>] )
{
-Stmt's to execute
}
To test defining a constructor explicitly, add a new class in the project naming it as “ConDemo.cs” and write
the below code in it:

class ConDemo {
public ConDemo() {
Console.WriteLine("Constructor is called.");
}
public void Demo() {
Console.WriteLine("Method is called.");
}
static void Main() {
ConDemo cd1 = new ConDemo();
ConDemo cd2 = new ConDemo();
ConDemo cd3 = cd2;
cd1.Demo(); cd2.Demo(); cd3.Demo();
Console.ReadLine();
}
}
Constructor of a class must be explicitly called for execution and we do that while creating the instance of
class as following:

Syntax: <Class_Name> <Instance_Name> = new <Constructor_Name>( [<List of Values>] )

Example: ConDemo obj = new ConDemo();


Calling the constructor

If constructor is called then only memory allocation is performed, so instances of a class will have memory
allocation because they call the constructor explicitly whereas reference of class will not have memory allocation
because they do not call the constructor.
Constructors are defined implicitly or explicitly?
Ans: Either Or

Constructors must be called explicitly or called implicitly?


Ans: Must be called explicitly
Constructors are of 2 types:
1. Default or Parameter-less
2. Parameterized

53
Constructors can also be parameterized i.e. just like a method can be defined with parameters, constructor
can also be defined with parameters. If constructor is defined with parameters we call it as “Parameterized
Constructor” where as a constructor without any parameters is called as “Default/Parameter-less Constructor”.

Default constructors can be defined either explicitly or will be defined implicitly provided there is no explicit
constructor defined under that class, whereas implicit constructors will never be parameterized i.e. if a constructor
is parameterized then it is very sure that it is an explicit constructor.
Note: if Constructors of a class are parameterized then values to those parameters should be sent while creating
instance of that class.
To test Parameterized Constructors, add a new class in our project naming it as “ParamConDemo.cs” and
write the below code in it:

class ParamConDemo
{
public ParamConDemo(int i)
{
Console.WriteLine("Parameterized constructor is called: " + i);
}
static void Main()
{
ParamConDemo cd1 = new ParamConDemo(10);
ParamConDemo cd2 = new ParamConDemo(20);
ParamConDemo cd2 = new ParamConDemo(20);
Console.ReadLine();
}
}
Why to define a constructor explicitly in our class when there are implicit constructors?
Ans: We define constructors explicitly in our class for various reasons like:

1. Implicit constructors are parameter-less which will initialize fields of a class either with a default value of
that type or a fixed given value even if we create multiple instances of class, whereas if constructors are
defined explicitly (parameterized), then we get a chance of passing new values to the fields every time the
instance of class is created. To test this, add a new class under our project naming it as “Second.cs” and
write the below code in it:

class Second
{
public int x;
public Second(int x)
{
this.x = x;
}
}

Note: “this” is a keyword which refers to the class and by using this we can access non-static members of a class
from other non-static blocks when there is a naming conflict.

54
Earlier we have defined a class "First" with a public field “x” in it, and we have initialized it with a static value
“100”, and in the above class also we have a public field “x” which was initialized thru a Constructor, so in the 1st
case even if we create multiple instances of class First; under every instance the value of “x” will be “100” only
whereas in case of class Second for each instance of class we create we can pass a new value for initialization because
initialization is performed thru the constructor. To test that add a new class in our project naming it as
“TestClasses.cs” and write the below code in it:
class TestClasses {
static void Main() {
First f1 = new First();
First f2 = new First();
First f3 = new First();
Console.WriteLine(f1.x + " " + f2.x + " " + f3.x);

Second s1 = new Second(100);


Second s2 = new Second(200);
Second s3 = new Second(300);
Console.WriteLine(s1.x + " "+ s2.x + " " + s3.x);
Console.ReadLine();
}
}

2. Every class requires some values for execution and the values that are required for a class to execute should
be passed to the class with the help of a constructor.
3. Just like parameters of a method will make a method dynamic, same as that parameters of constructor will
make the whole class dynamic.

Static Modifier
It is a keyword using which we can declare a class and its members as static i.e. if static keyword is prefixed
before a class or its members then they will become static or else by default every class and its member is non-static
only.

Members of a class are divided into 2 categories, like:


1. Non-Static or Instance Members
2. Static Members

Members that require instance of a class for initialization and execution are known as non-static or instance
members, whereas members that doesn't require instance of the class for initialization and execution are known as
static members.
Non-Static Fields Vs Static Fields:
• If a field is explicitly declared by using static modifier it is a static field, whereas rest of every other field is
non-static only.

class Test
{
int x = 100; //Non-Static

55
static int y = 200; //Static
static void Main()
{
int z = 300; //Static
}
}
Note: variables declared under static blocks are also static.
• Static fields of a class are initialized immediately once the execution of that class starts whereas non-static
fields are initialized only after creating the instance of that class as well as each and every time a new
instance is created.

• In the life cycle of a class a static field gets initialized 1 & only 1 time whereas a non-static field gets initialized
for “0” times if no instances are created & “n” times if “n” instances are created.

• The initialization of non-static fields is associated with a constructor call, so the best place to initialize non-
static fields is a constructor.

Note: static fields can also be initialized thru constructor but still we never do that because, it's a single copy thru
out the life cycle of class and every new instance will override the old values.
Constant Fields: If a field is explicitly declared by using “const” keyword we call it as a constant field and those
constant field can't be modified once after their declaration, so it is must to initialize them at the time of declaration
only because they do not have a default value.
E.g.: const float pi = 3.14f;

The behavior of a constant field will be very similar to the behavior of a static field i.e. initialized immediately
once the execution of class starts maintaining a single copy thru-out the life cycle of a class and the only difference
between static and constant fields is static fields can be modified but not constant fields.
ReadOnly Fields: If a field is explicitly declared by using readonly keyword we call it as a readonly field and like
constant fields, readonly fields also can't be modified, but after their initialization i.e. it's not mandatory to initialize
readonly fields at the time of declaration because they can also be initialized after their declaration i.e. under a
constructor.
E.g.: readonly bool flag;
The behavior of readonly fields will be similar to the behavior of non-static fields i.e. they are initialized only
after creating the instance of class and maintain a separate copy for each instance that is created.
The only difference between non-static and readonly fields is non-static fields can be modified but not
readonly fields.
The difference between constant and readonly fields is constant is a single fixed value for the whole class
whereas readonly is a fixed value specific to each instance of class.
To test all the above add a new class in our project naming it as “Fields.cs” and write the below code in it:

class Fields {
int x;
static int y = 200;
const float pi = 3.14f;
readonly bool flag;

56
public Fields(int x, bool flag) {
this.x = x;
this.flag = flag;
}
static void Main() {
Console.WriteLine("Static field y is: " + y);
Console.WriteLine("Constant field pi is: " + pi);
y = 500; //Can be modified
//pi = 5.67f; //Can't be modified & error if un-commented
Console.WriteLine("Modified static field y is: " + y);
Console.WriteLine("--------------------------------------------------");
Fields s1 = new Fields(50, true);
Fields s2 = new Fields(150, false);
Console.WriteLine("Non-Static Fields: " + (s1.x + " " + s2.x));
Console.WriteLine("ReadOnly Fields: " + (s1.flag + " " + s2.flag));
s1.x = 100; s2.x = 300; //Can be modified
//s1.flag = false; s2.flag = true; //Can't be modified & Error if un-commented
Console.WriteLine("Modified Non-Static Fields: " + (s1.x + " " + s2.x));
Console.ReadLine();
}
}

Note: While accessing fields of a class from other classes use class name for accessing static and constant fields
whereas use instance of class for accessing non-static and readonly fields.
• Static field initializes immediately once the execution of class starts maintaining a single copy thru out the
life cycle of class and its value is modifiable.
• Constant field also initializes immediately once the execution of class starts maintaining a single copy thru
out the life cycle of class and its value is non-modifiable.
• Non-static field initializes only after creating the instance of class, as well as for each instance of the class
that is created, maintaining a separate copy for each instance and its value is modifiable.
• Readonly field also initializes only after creating the instance of class, as well as for each instance of the
class that is created, maintaining a separate copy for each instance and its value is non-modifiable.
Non-Static Methods Vs Static Methods:
If a method is explicitly declared by using static keyword, then it is a static method whereas rest of every
other method is non-static only.
While defining methods, if a method is non-static and if we want to consume any static members of class
in it, we can consume them directly where as if the method is static, we can consume non-static members of class
in that method only by using class instance.

Rules for consuming members with in a class:


Static Member => Static Block //Direct Access

57
Static Member => Non Static Block //Direct Access
Non Static Member => Non Static Block //Direct Access
Non Static Member => Static Block //Can be accessed only by using the class instance

Rules for consuming members out of the class:


Static Members //Using class name
Non-Static Members //Using class instance
To test all the above add a new “Code File” in the project naming it as “TestMethods.cs” and write the
below code in it:

using System;
namespace OOPSProject {
class Methods {
int x = 200;
static int y = 100;
public void Add() {
Console.WriteLine(x + y);
}
public static void Sub() {
Methods m = new Methods();
Console.WriteLine(m.x - y);
}
}
class TestMethods {
static void Main() {
Methods obj = new Methods();
obj.Add(); //Add is non-static so calling it with instance
Methods.Sub(); //Sub is static so calling it with class name
Console.ReadLine();
}
}
}
Non-Static Constructor Vs Static Constructor:
• A Constructor if explicitly declared by using static modifier is a static Constructor whereas rest of the other
are non-static only and till now every Constructor we defined is non-static only.
• Static Constructors are implicitly called whereas non-static Constructors must be explicitly called.
• As we are aware that Constructors are responsible for initializing fields in a class; Non-Static Constructor
will initialize Non-Static and Readonly Fields, whereas Static Constructor will initialize Static and Constant
fields.
• Static Constructor executes immediately once the execution of class starts and more over it is the first block
of code to execute in a class, whereas Non-Static Constructor gets executed only after creating the instance
of class as well as each and every time a new instance is created i.e. Static Constructor executes 1 and only
1 time in the life cycle of a class whereas Non-Static Constructor get executed for “0” times if no instances
are created and “n” times if “n” instances are created.

58
• Static Constructor can't be parameterized because they are implicitly called and more over it's the first
block of code to execute in a class, so we don't have any chance of sending values to its parameter's where
as parameterized Non-Static Constructors can be defined.

Note: We have already learnt earlier that, every class will contain an implicit constructor if not defined explicitly and
those implicit constructors are defined based on the following criteria:
1. Non-static constructor will be defined in every class except in a static class.
2. Static constructor will be defined only if the class contains any static fields.
class Test //Case 1
{
}
*After compilation there will be a non-static constructor in class.
class Test { //Case 2
int i = 10;
}
*After compilation there will be a non-static constructor in class.
class Test { //Case 3
static int i = 100;
}
*After compilation there will be both static and non-static constructors also.
static class Test //Case 4
{
}
*After compilation there will not be any constructor in class.
static class Test { //Case 5
static int i = 100;
}
*After compilation there will be a static constructor in class.
To test all the above add a new class in the project naming it as “Constructors.cs” and write the below code
in it:

class Constructors {
static Constructors() {
Console.WriteLine("Static constructor is called.");
}
Constructors() {
Console.WriteLine("Non-static constructor is called.");
}
static void Main() {
Console.WriteLine("Main method is called.");
Constructors c1 = new Constructors();
Constructors c2 = new Constructors();
Constructors c3 = new Constructors();
Console.ReadLine();
}
}

59
Static Class: These are introduced in C# 2.0. If a class is explicitly declared by using static modifier we call it as a static
class and this class can contain only static members in it. We can't create the instance of static class and more over
it is not required also.

static class Class1


{
//Define only static members.
}
Note: Console is a static class in our Libraries so each and every member of Console class is static member only and
to check that, right click on Console class in Visual Studio.NET and choose the option “Go to definition” which will
open “Metadata” of that class.

Entity
Any living or non-living object which is associated with a set of attributes is known as an entity and
application development is all about dealing and managing these entities only. To develop an application we follow
the below process:

Step 1: Identify each and every entity that is associated with the application.
➢ School Application: Student, Teacher
➢ Banking Application: Customer, Employee

Step 2: Identify each and every attribute of that entity.


➢ Student: Id, Name, Address, Phone, Class, Section, Fees, Marks, Grade
➢ Teacher: Id, Name, Address, Phone, Qualification, Subject, Salary, Job
➢ Customer: Id, Name, Address, Phone, Balance, Account Type
➢ Employee: Id, Name, Address, Phone, Job, Salary, Department

Step 3: Design the DB based on the following guidelines:


1. Create a table representing each entity.
2. Every column of the table should represent each attribute of the entity.
3. Each record under table should be a unique representation for the entity.

Step 4: Design an application by using any Programming Language of our choice which should act as an UI (User
Interface) between the End User and Database in managing the data present under DB by adopting following
guidelines:
1. Define a class where each class should represent an entity.
2. Define properties where each property should be a representation for each attribute.
3. Each instance of the class we create will be a unique representation for each entity.

Inheritance
It is a process of consuming members that are defined in one class from other classes by establishing
parent/child relation-ship between the classes, so that child class can consume members of its parent class as if they
are owner of those members.

60
Note: Child class even if it can consume members of its parent class as an owner, still it can't access any private
members of their parent.

Syntax: [<modifiers>] class <CC Name> : <PC Name>


Example:
class Class1 {
-Define Members
}
class Class2 : Class1 {
-Consume members of parent from here
}
To test inheritance, add a new class under the project naming it as “Class1.cs” and write the below code in it:

class Class1 {
public Class1() {
Console.WriteLine("Class1 constructor is called.");
}
public void Test1() {
Console.WriteLine("Method 1");
}
public void Test2() {
Console.WriteLine("Method 2");
}
}
Now add another class in the project naming it as “Class2.cs” and write the below code in it:

class Class2 : Class1 {


public Class2() {
Console.WriteLine("Class2 constructor is called.");
}
public void Test3() {
Console.WriteLine("Method 3");
}
public void Test4() {
Console.WriteLine("Method 4");
}
static void Main() {
Class2 c = new Class2();

61
c.Test1(); c.Test2(); c.Test3(); c.Test4();
Console.ReadLine();
}
}
Rules and regulations that has to be followed while working with Inheritance:

Rule 1: In inheritance parent class Constructor must be accessible to child class or else inheritance will not be
possible. The reason why parent's Constructor should be accessible to child is, because when ever child class instance
is created, control first jumps to child class Constructor and child class Constructor will in turn call its parent class
Constructor for execution and to test this, place a break point at child class’s Main method and debug the code by
hitting F11.
The reason why child Constructor calls its parent class Constructor is, because if child class wants to
consume members of its parent class, they must be initialized first and then only child classes can consume them
and we are already aware that members of a class are initialized by its own Constructor.

Note: Constructors are never inherited i.e. Constructors are specific to any class which can initialize members of that
particular class only but not of parent or child classes.

When we create the instance of any class, it will first read all its parent classes to gather the information of
members that are present under those classes, so in our previous case when the instance of Class2 is created it
gathers information of Class1 also as following:

Rule 2: In inheritance child class can access members of their parent class whereas parent classes can never access
members of their child class which are purely defined under the child class. To test this re-write the code under Main
method of child class i.e. Class2 as following:
Class1 p = new Class1();
p.Test1(); p.Test2(); //Valid
//p.Test3(); p.Test4(); //Invalid and in-accessible
Console.ReadLine();
Rule 3: Earlier we have learnt that variable of a class can be initialized by using instance of same class to make it as
a reference, for example:
Class2 c1 = new Class2();
Class2 c2 = c1;
Same as the above we can also initialize variables of parent class by using its child classes instance as
following:
Class2 c = new Class2();
Class1 p = c;
In this case both parent class reference and child class instance will be accessing the same memory, but
owner of that memory is child class instance.

62
In the above case even if parent class reference is initialized by the child class instance and consuming the
memory of child class instance, now also it is not possible to access the member's which are purely defined under
the child class and to test that rewrite the code under Main method of child class i.e. Class2 as following:
Class2 c = new Class2();
Class1 p = c;
p.Test1(); p.Test2(); //Valid
//p.Test3(); p.Test4(); //Invalid and in-accessible now also
Console.ReadLine();

Note: We can never initialize child class variables by using parent class instance either implicitly or explicitly also.
Class1 p = new Class1(); //Creating parent class instance
Class2 c = p; //Invalid (Implicit conversion and compile time error)
Class2 c = (Class2)p; //Invalid (Explicit conversion and runtime error)

We can initialize any child class variable by using a parent class reference which is initialized by using the
same child class instance by performing an explicit conversion.

Creating parent's reference by using child class instance:


Class2 c = new Class2();
Class1 p = c;

Initializing child's variable by using the above parent's reference:


Class2 obj = (Class2)p; //Valid (Explicit)
or
Class2 obj = p as Class2; //Valid (Explicit)

Child Instance => Parent Reference //Valid


Child Instance => Parent Reference => Child Reference //Valid
Parent Instance => Child Reference //Invalid

Note: in the above case the new reference “obj” also start's accessing the same memory allocated for the instance
“c” and with the new reference we call the members of both “Class1” and “Class2” also.

63
Rule 4: Each and every class that is pre-defined or user-defined has a default parent class i.e. Object class of System
namespace. Object is the ultimate parent of all classes in .NET Framework class hierarchy providing low level services
to child classes. So every class by default contains 4 methods that are inherited from the “Object” Class and those
are “Equals”, “GetHashCode”, “GetType” and “ToString”, and these 4 methods can be called or consumed from any
class. To test this re-write code under Main method of child class (Class2) as following:

Object obj = new Object();


Console.WriteLine(obj.GetType() + "\n");
Class1 p = new Class1();
Console.WriteLine(p.GetType() + "\n");
Class2 c = new Class2();
Console.WriteLine(c.GetType());
Console.ReadLine();
Types of Inheritance: This talk about no. of child classes a parent have or the no. of parent classes a child have.
According to the standards of Object Oriented Programming we have 5 types of inheritances and they are:
i. Single
ii. Multi-Level
iii. Hierarchical
iv. Multiple
v. Hybrid

Rule 5: Both Java and .Net Language's doesn't provide the support for Multiple and Hybrid inheritances thru classes,
and what they support is Single, Multi-Level and Hierarchical inheritances because multiple inheritance suffers from
ambiguity problem, for example:

Note: CPP Language supports all 5 types of inheritances because it is the 1st Object Oriented Programming Language
that came into existence and at the time of its introduction, this problem was not anticipated.
Rule 6: In the first rule of inheritance we have discussed that whenever the instance of child class is created it will
implicitly call its parent class constructor for execution, but this implicit calling will take place only if parent classes
Constructor is “default or parameter less”, whereas if at all the parent classes Constructor is parameterized then
child class constructor can't implicitly call parent class Constructor for execution because it requires parameter
values for execution. To resolve the above problem developer needs to explicitly call parent classes Constructor from
child class constructor using "base" keyword and pass all the required parameter values.

To test the above re-write constructor of parent class i.e. Class1 as following:
public Class1(int i) {
Console.WriteLine("Class1 constructor is called: " + i);

64
}

Now when we run child class i.e. Class2, we get an error stating that there is no value sent to formal
parameter “i” of Class1 (Parent Class) and to resolve this problem re-write constructor of Class2 as following:
public Class2(int x) : base(x) {
Console.WriteLine("Class2 constructor is called.");
}

In the above case child classes constructor is also parameterized so while creating the instance of child class
we need to explicitly pass all the required values to its constructor and those values are first loaded into the
constructor and from there those values are passed to parent classes constructor thru the base keyword, and to test
this go to Main method of Class2, and re-write the code in it as following:
Class2 c = new Class2(50); Console.ReadLine();
How do we use inheritance in application development?
Ans: Inheritance is a process which comes into picture in the initial stages of an application development. As
discussed above, if we want to develop an Application we need to follow the below process:

Step 1: Identification of the entities.


E.g.: School Application: Student, TeachingStaff, NonTeachingStaff

Step 2: Identification of attributes for each entity.


Student Teaching Staff Non Teaching Staff
Id Id Id
Name Name Name
Phone Phone Phone
Address Address Address
Class Designation Designation
Section Salary Salary
Marks Qualification Dname
Fees Subject MgrId
Step 3: Designing the Database.

Step 4: Developing an application that works like an UI.


While developing the UI, to bring re-usability into the applications we use inheritance and to do that follow
the below guidelines:
1. Identify all the common attributes between entities and put them in a hierarchical order as below:

2. Now define classes based on the above hierarchy:

public class Person {


public int Id; public string Name, Phone, Address;

65
}
public class Student : Person {
int Class; char Section; float Marks, Fees;
}
public class Staff : Person {
public double Salary; public string Designation;
}
public class Teaching : Staff {
string Subject, Qualification;
}
public class NonTeaching : Staff {
int MgrId; string Dname;
}
Polymorphism
Behaving in different ways depending upon the input received is known as Polymorphism i.e. when ever
input changes then automatically the output or behaviour also changes accordingly. This can be implemented in our
language in 3 different ways:
1. Overloading
2. Overriding
3. Hiding/Shadowing

Overloading: This is again of different types like Method Overloading, Operator Overloading, Constructor
Overloading, Indexer Overloading and Deconstructor Overloading.

Method Overloading: It is an approach of defining multiple methods in a class with the same name by changing their
parameters. Changing parameters means we can change any of the following:

1. Change the no. of parameters passed to method.


2. Change the type of parameters passed to method.
3. Change the order of parameters passed to method.

• public void Show()


• public void Show(int i)
• public void Show(string s)
• public void Show(int i, string s)
• public void Show(string s, int i)

Note: in overloading a return type change with out parameter change is not taken into consideration, for example:
public string Show() => Invalid
To test method overloading, add a new class in the project naming it as OverloadMethods.cs and write the following
code in it:

class OverloadMethods {
public void Show() {
Console.WriteLine(1);

66
}
public void Show(int i) {
Console.WriteLine(2);
}
public void Show(string s) {
Console.WriteLine(3);
}
public void Show(int i, string s) {
Console.WriteLine(4);
}
public void Show(string s, int i) {
Console.WriteLine(5);
}
static void Main() {
OverloadMethods obj = new OverloadMethods();
obj.Show(); obj.Show(10); obj.Show("Hello"); obj.Show(10, "Hello"); obj.Show("Hello", 10);
Console.ReadLine();
}
}
What is Method Overloading?
Ans: It's an approach of defining a method with multiple behaviours and those behaviours will vary based on the
number, type and order of parameters. For example IndexOf is an overloaded method under String class which
returns the index position of a characater or string based on input values of that method, for example:
string str = "Hello World";
str.IndexOf('o'); => 4 => Returns the first occurance of character
str.IndexOf('o', 5); => 7 => Returns the next occurance of character

* WriteLine method of Console class is also overloaded for printing any type of value that is passed as input to the
method, as following:

• WriteLine()
• WriteLine(int value)
• WriteLine(bool value)
• WriteLine(double value)
• WriteLine(string value)
• WriteLine(string format, params object[] values)
• +13 more overloads
Inheritance based overloading: It's an approach of overloading parent classes’ methods under the child class, and
to do this child class doesn't require taking any permission from the parent class, for example:

Class1
public void Test()

Class2 : Class1
public void Test(int i)

67
Method Overriding: it’s an approach of re-implementing parent classes’ methods under child class exactly with the
same name and signature.

Difference between Method Overloading and Method Overriding:


Method Overloading Method Overriding
It's all about defining multiple methods with the same It's all about defining multiple methods with the same
name by changing their parameters. name and same parameters.
This can be performed with-in a class or between This can be performed only between parent/child
parent/child classes also. classes but can't be perfomed with-in a class.
To overload parent's method under child, child doesn't To override parent's method under child, parent should
require any permission from parent. first grant the permission to child.
This is all about defining multiple behaviours to a This is all about changing existing behaviour of a
method. parent's method under child.
How to override a parent classes method under child class?
Ans: To override any parent classes method under child class, first that method should be declared "overridable" by
using "virtual" modifier in parent class as following: Class1 => public virtual void Show() //Overridable

Every virtual method of parent class can be overriden by child class, if required by using "override" modifier
as following: Class2 : Class1 => public override void Show() //Overriding

Note: overriding virtual methods of parent class under child class is not mandatory for child class.

In overriding, parent class defines a method in it as virtual and gives it to the child class for consumption,
so that it's giving a permission to the child class either to consume the method “as is” or override the method as per
it's requirement, if at all the original behaviour of that method is not satisfactory to the child class.
To test inheritance based method overloading and method overriding, add a new class in the project naming
it as LoadParent.cs and write the following code in it:

class LoadParent {
public void Test() {
Console.WriteLine("Parent Class Test Method Is Called.");
}
public virtual void Show() {
Console.WriteLine("Parent Class Show Method Is Called.");
}
public void Display() {
Console.WriteLine("Parent Class Display Method Is Called.");
}
}
Now add another class in the project naming it as LoadChild.cs and write the following code in it:

class LoadChild : LoadParent {


//Overloading parent's Test method in child
public void Test(int i) {
Console.WriteLine("Child Class Test Method Is Called.");

68
}
static void Main() {
LoadChild c = new LoadChild();
c.Test(); //Executes parent class Test method
c.Test(10); //Executes child class Test method
c.Show(); //Executes parent class Show method
c.Display(); //Executes parent class Display method
Console.ReadLine();
}
}
Inheritance-Based Overloading: In the above classes Test method of parent class has been overloaded in child class
and then by using child class instance we are able to call both parent and child classes methods also, from the child
class.
Method Overriding: In the above classes Show method of parent class is declared virtual which gives a chance for
child classes to override that method but the child class did not override the method, so a call to that method by
using child classes instance will invoke the parent classes Show method only and this proves us overriding is only
optional and to confirm that run the child class LoadChild and watch the output of Show method.

In this case if child class overrides the parent classes virtual method then a call to that method by using
child class instance will execute or invoke its own method but not of the parent classes, and to test that add a new
method in class LoadChild as following:

//Overriding parent's Show method in child class


public override void Show() {
Console.WriteLine("Child Class Show Method Is Called.");
}

Now if we run the child class i.e. LoadChild and watch the output of Show method we will notice child
classes Show method getting executed in place of the parent classes Show method and this is what we call as
changing the behaviour.
Can we override any parent classes’ methods under child classes with out declaring them as virtual?
Ans: No.

Can we re-implement any parent classes’ methods under the child classes with out declaring them as virtual?
Ans: Yes.

We can re-implement a parent class method under the child class by using 2 different approaches:
• Overriding
• Hiding/Shadowing

Method Hiding/Shadowing: This is also an approach of re-implementing parent classes methods under child class
exactly with the same name and signature just like overriding but the difference between the 2 is; in overriding child
class can re-implement only virtual methods of parent class where as in-case of hiding/shadowing child class can re-
implement any method of the parent class i.e. even if the method is not declared as virtual also re-implementation
can be performed.

69
Class1 => public void Display()

Class2 : Class1 => public [new] void Display() //Hiding/Shadowing

In the above case using "new" keyword while re-implementing the method in child class is only optional
and if we don't use it, compiler gives a warning message at the time of compilation, telling that there is already a
method with the same name in parent class and your new method in child class will hide that old method, so by
using "new" keyword we are informing compiler that we are intentionally defining a new method with the same
name and signature under our child class.

Before testing hiding/shadowing first run the child class i.e. LoadChild and watch the output of Display
method and here we notice that parent classes Display method getting executed, now add a new method in the
child class LoadChild as following:
//Hiding/Shadowing parent's Display method in child
public new void Display() {
Console.WriteLine("Child Class Display Method Is Called.");
}

Now run the child class LoadChild again and watch the difference in output i.e. in this case child classes
Display() method is called in place of parent class Display() method.
In the above 2 classes we have performed the following:

LoadParent
public void Test()
public virtual void Show()
public void Display()

LoadChild : LoadParent
public void Test(int i) => Overloading
public override void Show() => Overriding
public new void Display() => Hiding/Shadowing
In case of Overriding and Hiding, after re-implementing the parent classes methods under child class,
instance of child class starts calling it's own methods but not of parent class, whereas if required there is still a chance
of calling those parent class methods from child class in 2 different ways:

1. By creating the parent classes instance under the child class we can call parent class methods from child
class and to test that re-write code under Main method of child class i.e. LoadChild as following:
LoadParent p = new LoadParent();
p.Show(); //Executes parent class Show method
p.Display(); //Executes parent class Display method

LoadChild c = new LoadChild();


c.Show(); //Executes child class Show method
c.Display(); //Executes child class Display method
Console.ReadLine();

70
2. By using base keyword also we can call parent class methods from child class, but keywords like "this" and
"base" can't be used in static blocks.

To test this first add 2 new methods under the child class i.e. LoadChild as following:

public void PShow() {


base.Show();
}
public void PDisplay() {
base.Display();
}
In the above case the 2 new methods we defined in child class acts as an interface in calling parent classes
methods from the child class, so now by using child class instance only we can call both parent and child classes
methods also. To test this re-write code under Main method of child class i.e. LoadChild as following:
LoadChild c = new LoadChild();
c.PShow(); //Executes parent class Show method
c.PDisplay(); //Executes parent class Display method
c.Show(); //Executes child class Show method
c.Display(); //Executes child class Display method
Console.ReadLine();
Note: Earlier in the 3rd rule of inheritance we have learnt that parent class reference even if created by using the
child class instance can't access any members of the child class which are purely defined under child class but we
have an exemption for that rule, that is, parent's reference can call or access overriden members of the child class
because overriden members are not considered as pure child class members because they have been re-
implemented with permission from the parent class. To test that re-write code under Main method of child class i.e.
LoadChild as following:

LoadChild c = new LoadChild();


LoadParent p = c;
p.Show(); //Executes child class Show method
p.Display(); //Executes parent class Display method
only
Console.ReadLine();

In the above case Display is considered as pure child class member only because it's re-implemented by
child class with out taking any permission from parent, so parent will never recognize it.

Polymorphism is divided into 2 types:


1. Static or Compile-time Polymorphism
2. Dynamic or Run-time Polymorphism

In static or compile-time polymorphism, the decision which polymorphic method has to be executed for a
method call is performed at compile time. Method overloading is an example for this and here compiler identifies
which overloaded method it has to execute for a particular method call at the time of program compilation by
checking the type and number of parameters that are passed to the method and if no method matchs the method
call it will give an error.

71
In dynamic or run-time polymorphism, the decision which polymorphic method has to be executed for a
method call is made at runtime rather than compile time. Run-time polymorphism is achieved by method overriding
because method overriding allows us to have methods in the parent and child classes with the same name and the
same parameters. By runtime polymorphism, we can point to any child class by using the reference of the parent
class which is initialized by child class object, so the determination of the method to be executed is based on the
instance being referred to by reference.
Static Polymorphism Dynamic Polymorphism
1. Occurs at compile-time. 1. Occurs at runtime.
2. Achieved through static binding. 2. Achieved through dynamic binding.
3. Method overloading should exist. 3. Method overriding should exist.
4. Inheritance is not involved. 4. Inheritance is involved.
5. Happens in the same class. 5. Happens between parent-child classes.
6. Reference creation thru instance is not required. 6. Requires parent class reference creation thru child
class instance.

Operator Overloading
It's an approach of defining mutiple behaviours to an operator, which varies based on the operands
between which we use the operator. For example: "+" is an addition operator when used between numeric operands
and it is a concatenation operator when used between string operands.
Number + Number => Addition
String + String => Concatenation
The behaviour for an operator is pre-defined i.e. developers of the language have already implemented,
logic that has to be executed when an operator is used between 2 operands under the libraries of a language with
the help of a special method known as "Operator Method".

Syntax of an Operator Method:


[<modifiers>] static <type> operator <opt>(<operand types>) {
-Logic
}
• Operator methods must be static only.
• <type> refers to the return type of method i.e. when the operator is used between 2 types what should be
the result type.
• operator is name of the method, which should be in lower case and can't be changed.
• <opt> refers to the operator for which we want to write behaviour like "+" or "-" or "==", etc.
• <operand types> refers to type of operands between which we want to use the operator.

Under FCL operator methods have been defined as following:


public static int operator +(int a, int b)
public static string operator +(string a, string b)
public static string operator +(string a, int b)
public static bool operator >(int a, int b)
public static float operator +(int a, float b)
public static decimal operator +(double a, decimal b)
public static bool operator ==(string a, string b)
public static bool operator !=(string a, string b)

72
Note: same as the above we can also define these operator methods for using an operator between new types of
operands.
To test Operator Overloading, Method Overriding and Method Hiding/Shadowing add a new class
“Matrix.cs” under the project and write the following code:

class Matrix {
int a, b, c, d; //Declaring attributes for a 2 * 2 Matrix
public Matrix(int a, int b, int c, int d) {
//Initializing attributes of the Matrix
this.a = a; this.b = b; this.c = c; this.d = d;
}
//Overriding the ToString() method inherited from Object class to return values of the Matrix in 2 * 2 format
public override string ToString() {
return a + " " + b + "\n" + c + " " + d + "\n";
}
//Implementing the + operator so that it can be used between 2 Matrix operands
public static Matrix operator +(Matrix obj1, Matrix obj2) {
Matrix obj = new Matrix(obj1.a + obj2.a, obj1.b + obj2.b, obj1.c + obj2.c, obj1.d + obj2.d);
return obj;
}
//Implementing the - operator so that it can be used between 2 Matrix operands
public static Matrix operator -(Matrix obj1, Matrix obj2) {
Matrix obj = new Matrix(obj1.a - obj2.a, obj1.b - obj2.b, obj1.c - obj2.c, obj1.d - obj2.d);
return obj;
}
//Re-Implementing the == operator using Hiding/Shadowing so that it can be used between 2 Matrix's, to perform
values == comparision b’coz original implementation for the operator in Object class is reference == comparision.
public static bool operator ==(Matrix obj1, Matrix obj2) {
if (obj1.a == obj2.a && obj1.b == obj2.b && obj1.c == obj2.c && obj1.d == obj2.d) {
return true;
}
else {
return false;
}
}
//Re-Implementing the != operator using Hiding/Shadowing so that it can be used between 2 Matrix's, to perform
values != comparision b’coz original implementation for the operator in Object class is reference != comparision.
public static bool operator !=(Matrix obj1, Matrix obj2) {
if (obj1.a != obj2.a || obj1.b != obj2.b || obj1.c != obj2.c || obj1.d != obj2.d) {
return true;
}
else {
return false;
}
}
}

73
ToString is a method defined in parent class "Object" and by default that method returns "Name" of the
type to which an instance belongs when we call it on any type's instance.
ToString() method is declared as virtual under the class “Object” so any child class can override it as per
their requirements as we performed it in our Matrix class to change the behaviour of that method, so the new
method will return values that are associated with Matrix but not the type name.
The "==" and "!=" operators are also implemented in the parent class “Object”, but their original behaviour
is to perform a reference equal and reference not-equal comparision between type instances but not values equal
and values non-equal comparision. We can also change the behaviour of those operator methods by using the
concept of hiding (but not overriding because they are not declared as virtual) as we have done in our Matrix class,
so that now the 2 operators will perform values equal and values not-equal comparision in place of reference equal
and reference not-equal comparision.
To consume all the above add a new class TestMatrix.cs and write the following code:

class TestMatrix {
static void Main() {
//Creating 4 instances of Matrix class with different values
Matrix m1 = new Matrix(20, 19, 18, 17); Matrix m2 = new Matrix(15, 14, 13, 12);
Matrix m3 = new Matrix(10, 9, 8, 7); Matrix m4 = new Matrix(5, 4, 3, 2);

//Performing Matrix Arithmatic


Matrix m5 = m1 + m2 + m3 + m4; Matrix m6 = m1 - m2 - m3 - m4;

//Printing values of each Matrix:


Console.WriteLine(m1); Console.WriteLine(m2); Console.WriteLine(m3);
Console.WriteLine(m4); Console.WriteLine(m5); Console.WriteLine(m6);

//Performing Matrix equal comparision


if (m1 == m2) { Console.WriteLine("Yes, m1 is equal to m2."); }
else { Console.WriteLine("No, m1 is not equal to m2."); }

//Performing Matrix not equal comparision


if (m1 != m2) { Console.WriteLine("Yes, m1 is not equal to m2."); }
else { Console.WriteLine("No, m1 is equal to m2."); }
Console.ReadLine();
}
}

In the above case when we call WriteLine method by passing Matrix class instance as a parameter to it, will
internally invoke the overloaded WriteLine Method which takes "Object" as a parameter and that method will
internally call ToString() method on that instance, and because we have overwritten the ToString method in our
Matrix class, a call to it in WriteLine method will invoke Matrix classes ToString method which will return the values
that are associated with Matrix instance and prints them in a 2 * 2 Matrix format.

Constructor Overloading
Just like methods in a class can be overloaded, constructors in a class also can be overloaded and it is called
as constructor overloading. It's an approach of defining multiple constructors under a class and if constructors of a

74
class are overloaded then instance of that class can be created by using any available constructor i.e. it is not
mandatory to call any particular constructor for instance creation. To test this, add a new code file under the project
naming it as TestOverloadCons.cs and write the following code in it:

using System;
namespace OOPSProject {
class OverloadCons {
int i; bool b;
public OverloadCons() {
//Initializes both i & b with default values
}
public OverloadCons(int i) {
//Initializes i with given value and b with default value
this.i = i;
}
public OverloadCons(bool b) {
//Initializes i with default value and b with given value
this.b = b;
}
public OverloadCons(int i, bool b) {
//Initializes both i & b with given values
this.i = i; this.b = b;
}
public void Display() {
Console.WriteLine("Value of i is: {0} and value of b is: {1}", i, b);
}
}
class TestOverloadCons {
static void Main() {
OverloadCons c1 = new OverloadCons(); c1.Display();
OverloadCons c2 = new OverloadCons(10); c2.Display();
OverloadCons c3 = new OverloadCons(true); c3.Display();
OverloadCons c4 = new OverloadCons(10, true); c4.Display();
Console.ReadLine();
}
}
}

By overloading constructors in a class we get a chance to initialize fields of that class in 3 different ways:
1. With a default or “parameter-less” constructor defined in class we can initialize all fields of that class with
default values.
2. With a parameterized constructor defined in class we can initialize all fields of that class with given values.
3. With a parameterized constructor defined in class we can initialize some fields of that class with default
values and some fields with given values.

75
Note: If a class contains multiple attributes in it and if we want to initialize them in a “mix & match” combination
then we overload constructors, and the no. of constructors to be defined will be 2 power “n” where “n” is the no. of
attributes. In our above class we have 2 attributes so we have defined 4 constructors.

Copy Constructor
It is a constructor using which we can create a new instance of the class with the help of an existing instance
of the same class, which copies the attribute values from the existing instance into the new instance and the main
purpose of this constructor is to initialize a new instance with the values from an existing instance. The “Formal
Parameter Type” of a copy constructor will be the same “Class Type” in which it is defined.

To test Copy Constructors add a new class under the project naming it as CopyConDemo.cs and write the
following code:

class CopyConDemo {
int Custid; string Name; double Balance;
public CopyConDemo(int Custid) {
this.Custid = Custid; this.Name = "Scott"; this.Balance = 5000.00;
}
public CopyConDemo(CopyConDemo cd) //Copy Constructor {
this.Custid = cd.Custid; this.Name = cd.Name; this.Balance = cd.Balance;
}
public void Display() {
Console.WriteLine("Custid: {0}; Name: {1}; Balance: {2}", Custid, Name, Balance);
}
static void Main() {
CopyConDemo cd1 = new CopyConDemo(101);
CopyConDemo cd2 = new CopyConDemo(cd1); //Calling Copy Constructor
cd1.Display(); cd2.Display(); Console.WriteLine();
cd1.Balance = 10000.00; cd1.Display(); cd2.Display(); Console.WriteLine();
cd2.Balance = 20000.00; cd1.Display(); cd2.Display(); Console.ReadLine();
}
}
In the above case “cd2” is a new instance of the class which is created by copying the values from “cd1” and
here any changes that are performed on members of “cd1” will not reflect to members of “cd2” and vice versa
because they have their own individual memory which is not accessbile to others.

Types of Constructors: constructors are divided into 5 Categories like:

1. Default Constructor
2. Parameterized Constructor
3. Copy Constructor
4. Static Constructor
5. Private Constructor

76
Default Constructor: a constructor defined with out any parameters is known as a default constructor, which will
initialize fields of a class with default values. If a class is not defined with any explicit constructor then the class will
contain an implicit default constructor.

Parameterized Constructor: if a constructor is defined with atleast 1 parameter then we call it as parameterized
constructor and these constructors must be explicitly defined but never implicitly defined. Parameterized
constructors are used for initializing fields of a class with given set of values which we can pass while creating the
instance of that class.

Copy Constructor: it’s a constructor which takes the same type as its “Parameter” and initializes the fields of class
by copying values from an existing instance of the same class. A Copy constructors will not create a reference to the
class i.e. it will create a new instance for the class by allocating memory for all the members of that class and very
importantly any changes made on the source will not reflect to the new instance and vice-versa.

Static Constructor: if a constructor is defined explicitly by using static modifier we call it as a static constructor and
this constructor is the first block of code which executes under the class and they are responsible for initializing static
fields and more over these constructors can't be overloaded because they can't be parameterized. This constructor
is called implicitly before the first instance is created or any static members are referenced.
Private Constructor: If a constructor is explicitly declared by used private modifier we call it as a private constructor.
If a class contains only private constructors and no public constructors, other classes cannot create instances of that
class. The use of private constructor is to serve singleton classes where a singleton class is one which limits the
number of instances created to one.
Sealed Class: if a class is explicitly declared by using sealed modifier we call it as a sealed class and these classes can't
be inherited by other classes, for example:

sealed class Class1 {


-Members
}

In the above case Class1 is a sealed class so it can’t be inherited by any other class, for example:
class Class2 : Class1 => Invalid

Note: even if a sealed class can't be inherited it is still possible to consume the members of a sealed class by creating
its instance, for example String is a sealed class in our FCL, so we can't inherit from that class but we can still consume
it in all our classes by creating the instance of String class.

Sealed Method: If a parent class method can't be overriden under a child class, then we call that method as Sealed
Method. By default every method of a class is sealed because we can never override any method of parent class
under the child class unless the method is declared as virtual. If a method is declared as virtual under a class then
any child class of it in a linear hierarchy can override that method, for example:
Class1
public virtual void Show()

Class2 : Class1
public override void Show() //Valid

77
Class3 : Class2
public override void Show() //Valid

Note: in the above case even if Class2 is not overriding the method, then also Class3 can override the method.

When a child class is overriding any of its parent classes’ virtual methods, it can seal those methods by using
sealed modifier on them, so that furthur overriding of those methods can't be performed by its child classes, for
example:
Class1
public virtual void Show()

Class2 : Class1
public sealed override void Show() //Valid

Class3 : Class2
public override void Show() //Invalid
Note: in the above case Class2 has sealed the method while overriding the method so Class3 can’t override the
method.
Abstract Class and Abstract Method
Abstract Method: a method without any method body is known as abstract method i.e. an abstract method contains
only declaration without any implementation. To declare a method as abstract it is must to use “abstract” modifier
on that method explicitly.

Abstract Class: a class under which we declare abstract members is known as abstract class and must be declared
by using “abstract” modifier.

abstract class Math {


public abstract void Add(int x, int y);
}

Note: each and every abstract member of an abstract class must be implemented by the child of abstract class
without fail (mandatory).

The concept of abstract method's is near similar to method overriding i.e. in case of overriding, if at all a
parent class contains any methods declared as virtual then child classes can re-implement those methods by using
override modifier whereas in case of abstract methods if at all a parent class contains any methods declared as
abstract then every child class must implement all those methods by using the same override modifier only.

78
An abstract class can contain both abstract and non-abstract (concrete) members also, and if at all any child
class of the abstract class wants to consume any non-abstract members of its parent, must first implement all the
abstract members of its parent.

Abstract Class:
• Non-Abstract/Concrete Members
• Abstract Members

Child Class of Abstract Class:


• Implement each and every abstract member of parent class
• Now only we can consume concrete members of parent class

Note: we can't create the instance of an abstract class, so abstract classes are never useful to themselves, i.e an
abstract class is always a parent providing services to their child classes.
To test an abstract class and abstract methods add a new class under the project naming it as
“AbsParent.cs” and write the following code in it:
abstract class AbsParent {
public void Add(int x, int y) {
Console.WriteLine(x + y);
}
public void Sub(int x, int y) {
Console.WriteLine(x - y);
}
public abstract void Mul(int x, int y);
public abstract void Div(int x, int y);
}

Now add another class “AbsChild.cs” to implement the above abstract classes - abstract methods and write
the following code in it:

class AbsChild : AbsParent {


public override void Div(int x, int y) {
Console.WriteLine(x / y);
}
public override void Mul(int x, int y) {
Console.WriteLine(x * y);

79
}
static void Main() {
AbsChild c = new AbsChild();
c.Add(100, 23); c.Sub(78, 19); c.Mul(15, 18); c.Div(580, 24);
Console.ReadLine();
}
}

Note: even if the instance of an abstract class can't be created it is still possible to create the reference of an abstract
class by using it's child classes instance, and with that reference we can call each and every concrete method of
abstract class as well as its abstract methods which are implemented by child class, and to test this re-write code
under Main method of class “AbsChild” as following:

AbsChild c = new AbsChild();


AbsParent p = c;
p.Add(100, 23); p.Sub(78, 19); p.Mul(15, 18); p.Div(580, 24);
Console.ReadLine();
What is the need of Abstract Classes and Abstract Methods?
Ans: The concept of Abstract Classes and Abstract Methods is an extension to inheritance i.e. in inheritance we have
already learnt that, we can eliminate redundancy between entities by identifying all the common attributes between
the entities we wanted to implement, by defining them under a parent class.

For example if we are designing a Mathematical Application then we follow the below process of implementation:

Step1: Identifying the Entities of Mathematical Application.


• Cone, Circle, Triangle, Rectangle
Step 2: Identifying the Attributes of Entities
• Cone: Height, Radius, Pi
• Circle: Radius, Pi
• Triangle: Base (Width), Height
• Rectangle: Length (Height), Breadth (Width)

Step 3: Designing the database by following the rules we learnt in entity implementations.

Step 4: Develop an application and define classes representing each and every entity.

Note: while defining classes representing entities, as learnt in inheritance first we need to define a parent class with
all the common attributes as following:

80
In the above case, “Figure” is a Parent class containing all the common attributes between the 4 entities.
Now we want a method that returns Area of each and every figure, and even if the method is common for all the
classes, still we can't define it in the parent class Figure, because the formula to calculate area varies from figure to
figure. So to resolve the problem, without defining the method in parent class we need to declare it in the parent
class Figure as abstract and restrict each and every child class to implement logic for that method as per their
requirement as following:

In the above case because GetArea() method is declared as abstract, it is mandatory for all the child classes
to implement that method under them, but logic can be varying from each other whereas signature of the method
can't change and now all the child classes have to do the following:
1. Define a constructor to initialize the attributes that are required for that entity.
2. Implement GetArea() method and write logic for calculating the Area of that corresponding figure.

To test the above add a new “Code File” under project naming it as “TestFigures.cs” and write the following code:

using System;
namespace OOPSProject {
public abstract class Figure {
public double Width, Height, Radius;
public const float Pi = 3.14f;
public abstract double GetArea();
}
public class Cone : Figure {
public Cone(double Radius, double Height) {
this.Radius = Radius; this.Height = Height;
}
public override double GetArea() {
return Pi * Radius * (Radius + Math.Sqrt((Height * Height) + (Radius * Radius)));
}
}
public class Circle : Figure {
public Circle(double Radius) {
this.Radius = Radius;
}
public override double GetArea() {
return Pi * Radius * Radius;
}
}
public class Triangle : Figure {
public Triangle(double Base, double Height) {

81
this.Width = Base; this.Height = Height;
}
public override double GetArea() {
return 0.5 * Width * Height;
}
}
public class Rectangle : Figure {
public Rectangle(double Length, double Breadth) {
this.Width = Length; this.Height = Breadth;
}
public override double GetArea() {
return Width * Height;
}
}
class TestFigures {
static void Main() {
Cone cone = new Cone(12.54, 67.34);
Console.WriteLine("Area of Cone: " + cone.GetArea());
Circle circ = new Circle(45.29);
Console.WriteLine("Area of Circle: " + circ.GetArea());
Triangle trin = new Triangle(67.32, 56.98);
Console.WriteLine("Area of Triangle: " + trin.GetArea());
Rectangle rect = new Rectangle(29.45, 32.78);
Console.WriteLine("Area of Rectangle: " + rect.GetArea());
Console.ReadLine();
}
}
}
Interface
Interface is also a user-defined type like a class but can contain only “Abstract Members” in it and all those
abstract members should be implemented by a child class of the interface.

Non-Abstract Class: Contains only non-abstract/concrete members


Abstract Class: Contains both non-abstract/concrete and abstract members
Interface: Contains only abstract members

Just like a class can have another class as its parent, it can also have an interface as its parent but the main
difference is if a class is a parent we call it as inheriting whereas if an interface is a parent we call it as implementing.

Inheritance is divided into 2 categories:


1. Implementation Inheritance
2. Interface Inheritance

If a class is inheriting from another class we call it as Implementation Inheritance whereas if a class is
implementing an interface we call it as Interface Inheritance. Implementation Inheritance provides re-usability

82
because by inheriting from a class we can consume members of a parent in child class whereas Interface Inheritance
doesn't provide any re-usability because in this case we need to implement abstract members of a parent in child
class, but not consume.

Note: we have already discussed in the 5th rule of inheritance that Java and .Net Languages doesn't support multiple
inheritance thru class, because of ambiguity problem i.e. a class can have 1 and only 1 immediate parent class to it;
but both in Java and .Net languages multiple inheritance is supported thru the interfaces i.e. a class can have more
than 1 interface as its immediate parent.

Syntax to define a interface:


[<modifiers>] interface <Name> {
-Abstract member declarations.
}
• We can't declare any fields under an interface.
• Defualt scope for members of an interface is public whereas it is private in case of a class.
• Every member of an interface is by default abstract, so we again don't require using abstract modifier on it.
• Just like a class can inherit from another class, an interface can also inherit from another interface, but not
from a class.

Adding an Interface under Project: Just like we have “Class Item Template” in “Add New Item” window to define a
class we are also provided with an “Interface Item Template” to define an Interface. To test working with interfaces
add 2 interfaces under the project naming them as IMath1.cs, IMath2.cs and write the following code:
interface IMath1 { interface IMath2 {
void Add(int a, int b); void Mul(int a, int b);
void Sub(int a, int b); void Div(int a, int b);
} }

To implement methods of both the above interfaces add a class under project naming it as ClsMath.cs and
write the following code:

class ClsMath : Program, IMath1, IMath2 {


public void Add(int a, int b) {
Console.WriteLine(a + b);
}
public void Sub(int a, int b) {
Console.WriteLine(a - b);
}
public void Mul(int a, int b) {
Console.WriteLine(a * b);
}
public void Div(int a, int b) {

83
Console.WriteLine(a / b);
}
static void Main() {
ClsMath obj = new ClsMath();
obj.Add(100, 34); obj.Sub(576, 287); obj.Mul(12, 38); obj.Div(456, 2);
Console.ReadLine();
}
}

Points to Ponder:
1. The implementation class can inherit from another class and also implement “n” no. of interfaces, but class
name must be first in the list followed by interface names.
E.g.: class ClsMath : Program, IMath1, IMath2
2. While declaring abstract members in an interface we don't require using “abstract” modifier on them and
in the same way while implementing those abstract members we don't require to use “override” modifier
also.

Just like we can't create instance of an abstract class, we can't create instance of an interface also; but here
also we can create a reference of interface by using it's child class instance and with that reference we can call all
the members of parent interface which are implemented in child class and to test this re-write code under Main
method of class “ClsMath” as following:

ClsMath obj = new ClsMath();


IMath1 i1 = obj; IMath2 i2 = obj;
i1.Add(100, 34); i1.Sub(576, 287);
i2.Mul(12, 38); i2.Div(456, 2);
Console.ReadLine();
Multiple Inheritance with Interfaces:
Earlier in the 5th rule of inheritance we have discussed that Java and .Net Languages doesn't support
multiple inheritances thru classes because of ambiguity problem.

Whereas in Java and .Net Languages multiple inheritance is supported thru interfaces i.e. a class can have
any no. of interfaces as its parent, but still we don't come across any ambiguity problem because child class of an
interface is not consuming parent's members but implements them.

84
If we come across any situation as above we can implement the interface methods under class by using 2
different approaches:
1. Implement the method of both interfaces only for 1 time under the class and both interfaces will assume
the implemented method is of its only and in this case we can call the method directly by using class
instance.
2. We can also implement the method of both interfaces separately for each interface under the class by pre-
fixing interface name before method name and we call this as explicit implementation, but in this case we
need to call the method by using reference of interface that is created with the help of a child class instance.

To test the above add 2 new interfaces under the project naming them as Interface1.cs, Interface2.cs and
write the following code:
interface Interface1 { interface Interface2 {
void Test(); void Test();
void Show(); void Show();
} }

Now add a new class under the project naming it as ImplClass.cs for implementing both the above interfaces
and write the following code:

class ImplClass : Interface1, Interface2 {


public void Test() { //Implementing Test method using 1st approach
Console.WriteLine("Method declared under 2 interfaces.");
}
void Interface1.Show() { //Implementing Show method using 2nd approach
Console.WriteLine("Method declared under Interface1.");
}
void Interface2.Show() { //Implementing Show method using 2nd approach
Console.WriteLine("Method declared under Interface2.");
}
static void Main() {
ImplClass obj = new ImplClass();
obj.Test();
Interface1 i1 = obj; Interface2 i2 = obj;
i1.Show(); i2.Show();
Console.ReadLine();
}
}

Structure
Structure is also a user-defined type like a class, which can contain members what a class can contain like
constructor, static constructor, constants, fields, methods, properties, indexers, operators and events.

Differences between Class and Structure


Class Structure
This is a reference type. This is a value type.

85
Memory is allocated for its instances on Managed Heap Memory is allocated for its instances on Stack, so
so we get the advantage of Automatic Memory Automatic Memory Management is not available but
Management thru Garbage Collector. faster in access.
Recommended for representing entities with larger Recommended for representing entities with smaller
volumes of data. volumes of data.
All pre-defined reference types in our FCL like string All pre-defined value types in our FCL like int
(System.String) and object (System.Object) are defined (System.Int32), float (System.Single), bool
as classes. (System.Boolean), char (System.Char) and Guid
(System.Guid) are defined as structures.
"new" keyword is mandatory for creating the instance "new" keyword is optional for creating the instance and
and in this process we need to call any constructor that if "new" is not used it will call default constructor which
is available in the class. is defined implicitly, whereas it is still possible to use
"new" and call other constructors also.
Contains an implicit default constructor if no Contains an implicit default constructor every time.
constructor is defined explicitly.
We can declare fields and those fields can be initialized We can declare fields but those fields can't be initialized
at the time of declaration. at the time of declaration.
Fields can also be initialized thru a constructor as well Fields can only be initialized thru a constructor as well
as referring thru instance also we can initialize them. as referring thru instance also we can initialize them.
Constructor is mandatory for creating the instance Default constructor is mandatory for creating the
which can either be default or parameterized also. instance without using new keyword and apart from
that we can also define parameterized constructors.
Developers can define any constructor like default or Developers can define parameterized constructors only
parameterized also, or else implicit default constructor because there is always an implicit default constructor,
gets defined. and this default constructor is mandatory if at all we
want to create instance without using "new" keyword.
If defined with “0” constructors after compilation there If defined with “0” constructors after compilation here
will be “1” constructor and if defined with “n” also there will be “1” constructor whereas if defined
constructors after compilation there will be “n” with “n” constructors after compilation there will be “n
constructors only. + 1” constructors.
Supports both, implementation as well as interface Supports only interface inheritance but not
inheritances also i.e. a class can inherit from another implementation inheritance i.e. a structure can
class as well as implement an interface also. implement an interface but can never inherit from
another structure.
Syntax to define a structure:
[<modifiers>] struct <Name> {
-Define Members
}

Adding a Structure under Project: we are not provided with any Structure Item template in the add new item
window, like we have class and interface item templates, so we need to use code file item template to define a
structure under the project. Add a Code File under project, naming it as “MyStruct.cs” and write the following in it:

using System;
namespace OOPSProject {

86
struct MyStruct {
int x;
public MyStruct(int x) {
this.x = x;
}
public void Display() {
Console.WriteLine("Method in a structure: " + x);
}
static void Main() {
MyStruct m1 = new MyStruct(); m1.Display();
MyStruct m2; m2.x = 10; m2.Display();
MyStruct m3 = new MyStruct(20); m3.Display();
Console.ReadLine();
}
}
}
Consuming a Structure: we can consume a Structure and its members from another structure or a class also; but
only by creating its instance because structure doesn't support inheritance. To test this, add a new class under the
project naming it as “TestStruct.cs” and write the following code:

class TestStruct {
static void Main() {
MyStruct obj = new MyStruct(50);
obj.Display();
Console.ReadLine();
}
}
Extension Methods
It's a new feature added in CSharp 3.0 which allows adding new methods to existing types (class/structure)
without creating a new derived type or re-compiling or modifying the original type. Extension methods are a special
kind of static methods, but they are called or consumed as if they are non-static methods. There is no difference
between calling an extension method and methods that are directly defined in the type.
Rules for defining Extension Methods:
1. Extension methods should be defined in a static class only.
2. The first parameter of an extension method is the type name to which the method has to be bound with,
pre-fixed by “this” keyword and we call this parameter as binding parameter which will not be taken into
consideration while calling the method.
3. We can also define any additional parameters (formal parameters) to an extension method from 2nd place
of parameter list and all those parameters will be taken into consideration while calling the method.
Note: If an extension method is defined with “n” no. of parameters, while calling the method there will be
“n - 1” parameters only, because it excludes the binding parameter.
4. We can't bind an extension method with multiple types because it can have only 1 binding parameter.
5. Extension methods can't access private members in the original type, but can access other members.
6. If we create an extension method which has the same signature method inside the original type we are
extending, then the extension method will not be called.

87
To test Extension Methods add a new class naming it as ExtensionMethods.cs and write the following code:
static class ExtensionMethods {
public static void Test5(this Program p, int i) { //Adding extension method to user-defined class Program
Console.WriteLine("Extension Method into Program class: " + i);
}
public static void Show(this MyStruct m) { //Adding extension method to user-defined structure MyStruct
Console.WriteLine("Extension method into MyStruct structure.");
}
public static ulong Factorial(this UInt32 i) { //Adding extension method to pre-defined structure UInt32
if (i == 0 || i == 1) { return 1; }
if (i == 2) { return 2; }
else { return i * Factorial(i - 1); }
}
public static string ToPascal(this String OldStr) { //Adding extension method to pre-defined class (Sealed Class)
if (OldStr.Trim().Length > 0) {
string NewStr = null;
OldStr = OldStr.ToLower();
string[] sarr = OldStr.Split(' ');
foreach (string str in sarr) {
char[] carr = str.ToCharArray(); carr[0] = char.ToUpper(carr[0]);
if (NewStr == null) { NewStr = new String(carr); }
else { NewStr += " " + new String(carr); }
}
return NewStr;
}
return OldStr;
}
Now add a new class TestExtensionMethods.cs and write the following:
class TestExtensionMethods {
static void Main() {
Program p = new Program(); p.Test5(100);
MyStruct obj = new MyStruct(); obj.Show();
uint fact = 15; ulong result = fact.Factorial(); Console.WriteLine($"Factorial of {i} is: {result}");
string str = "hElLo hOw aRe yoU"; str = str.ToPascal(); Console.WritLine(str); Console.ReadLine();
}
}

Working with Multiple Projects and Solution


While developing an application sometimes code will be written under more than 1 project also, where
collection of those projects is known as a Solution. Whenever we open a new project by default VS will create one
Solution and under it the project gets added, where a solution is a collection of projects and project is a collection
of items.

A Solution also requires a name, which can be specified by us while opening a new project or else will take
name of the first project that is created under solution, if not specified. In our case solution name is OOPSProject
because our project name is OOPSProject. A solution can have projects of different .NET languages as well as can be

88
of different project templates also like Windows Application, Console Application, Class Library etc. but a project
cannot contain items of different .NET languages i.e. they must be specific to one language only.

To add a new project under our OOPSProject solution, right click on solution node in Solution Explorer and
select add “New Project” which opens the new project window, under it select language as Visual C#, template as
Console Application, name the project as “SecondProject” and click ok which adds the new project under the
OOPSProject solution.

By default the new project also comes with a class Program but under SecondProject namespace, now write
following code in its main method and execute:
Console.WriteLine(“Second Project under the solution.”);
Console.ReadLine();

To run the above class, first we need to set a property “StartUp Project”, because there are multiple
project's under the solution and VS by default runs first project of the Solution only i.e. OOPSProject under the
solution. To set the “StartUp Project” property and run classes under SecondProject open Solution Explorer, right
click on SecondProject, select “Set as StartUp Project” and then run the project.

Note: if the new project is added with new classes we need to again set “StartUp Object” property under Second
Projects property window, because each project has its own property window.
Saving Solution and Projects:
The application what we have created right now is saved physically on hard disk in the same hierarchy as
seen under Solution Explorer i.e. first a folder is created representing the solution and under that a separate folder
is created representing each project and under that items corresponding to that project gets saved as following:

<drive>:\<our_folder>\OOPSProject\OOPSProject => Project1


<drive>:\<our_folder>\OOPSProject\SecondProject => Project2
Note: a solution will be having a file called solution file, which gets saved with .sln extension and a project also has
a file called project file, where a C# Project file gets saved with .csproj extension which can contain C# items only.
Compilation of Projects:
Whenever a project is compiled it generates an output file known as Assembly that contains IL Code of all
the “Types” that are defined in the project. The name of Assembly file will be same as the project name and will
have an extension of either “.exe” or “.dll”.

Note: extension of an assembly is based on the type of project we have opened.

Assembly files are what we carry on to client systems when the application has to be deployed there, so
they are referred as units of deployment. All FCL were installed on our machines in the form of assemblies only. The
assembly file of a project will be present under bin\Debug\netcoreapp3.1 folder of that project's folder.

<drive>:\<our_folder>\OOPSProject\OOPSProject\bin\Debug\netcoreapp3.1\OOPSProject.exe => Assembly1


<drive>:\<our_folder>\OOPSProject\SecondProject\bin\Debug\netcoreapp3.1\SecondProject.exe => Assembly2

ildasm: Intermediate Language Dis-Assembler. We use it to dis-assemble an Assembly file and view the contents of
it. To check it out, open Visual Studio Command Prompt, go to the location where the assembly files of the project
are present and use it as following:

89
ildasm <name of the assembly file>
E.g.: Open Visual Studio Command Prompt, go to the below location and try the following:
<drive>:\<our_folder>\OOPSProject\OOPSProject\bin\Debug\netcoreapp3.1> ildasm OOPSProject.exe
<drive>:\<our_folder>\OOPSProject\SecondProject\bin\Debug\netcoreapp3.1> ildasm SecondProject.exe
Q. Can we consume classes of a project from other classes of same project?
Ans: Yes, we can consume them directly because all those classes were under same project and will be considered
as a family.

Q. Can we consume the classes of a project from other projects?


Ans: Yes, we can consume but not directly, as they are under different projects. To consume them first we need to
add reference of the assembly in which the class is present to the project who wants to consume it.

Q. How to add the reference of an assembly to a project?


Ans: To add reference of an assembly to a project open solution explorer, right click on the project to whom
reference has to be added, select “Add => Project Reference” option, which opens a window “Reference Manager”,
in that select “Browse” option on LHS, then click on “Browse” button below and select the assembly we want to
consume from its physical location and click ok. Now we can consume types of that assembly by referring with their
namespace or importing the namespace.

To test this go to OOPSProject Solution, right click on the SecondProject we have newly added, select add
reference and add the reference of OOPSProject assembly from its physical location. Now add a new class under the
SecondProject naming it as Class1.cs and write the following code in it:

using OOPSProject;
class Class1 {
static void Main() {
Rectangle r = new Rectangle(12.34, 56.78); Console.WriteLine(r.GetArea());
Circle c = new Circle(34.56); Console.WriteLine(c.GetArea());
Cone cc = new Cone(12.67, 34.89); Console.WriteLine(cc.GetArea());
Triangle t = new Triangle(45.23, 98.42); Console.WriteLine(t.GetArea());
Console.ReadLine();
}
}
Assemblies and Namespaces:
An assembly is an output file which gets generated after compilation of a project and it is physical. The
name of an assembly file will be same as project name and can't be changed at all.
Project: Source Code Assembly: Compiled Code (IL Code)
A namespace is a logic container of types which are used for grouping types. By default every project has a
namespace and its name is same as the project name, but we can change namespace names as per our requirements
and more over a project can contain multiple namespaces in it also.

For Example: TestProject (Console Applicaion) when compiled generates an assembly with the name as
TestProject.exe, under it namespaces can be as following:

namespace NSP1 {
Class1

90
Class2
}
namespace NSP2 {
Class3
Class4
}
Whenever we want to consume a type which is defined under a project from other projects first we need
to add reference of the assembly corresponding to that project and then only we can consume types of that assembly
in the new project. While consuming types in the assembly for which reference is added we need to prefix type
names with their namespace or import the namespace and consume the types.

Access Specifier’s
These are a special kind of modifiers using which we can define the scope of a type and its members i.e.
who can access them and who cannot. C# supports 5 access specifiers in it, those are:
1. Private 2. Internal 3. Protected 4. Protected Internal 5. Public 6. Private Protected (C# 7.3)
Note: members that are defined in a type with any scope or specifier are always accessible with in the type,
restrictions comes into picture only when we try to access them outside of the type.

Private: members declared as private under a class or structure can be accessed only with-in the type in which they
are defined and more over their default scope is private only. Interfaces can't contain any private members and their
default scope is public. Types can’t be declared as private, so this applies only to members.

Protected: members declared as protected under a class can be accessed only from their child class i.e. non-child
classes can't consume them. Types can’t be declared as protected, so this applies only to members.

Internal: members and types that are declared as internal can be consumed only with in the project, both from a
child or non-child. The default scope for a type in C# is internal only.
Protected Internal: members declared as protected internal will have dual scope i.e. within the project they behave
as internal providing access to whole project and out-side the project they will change to protected and provide
access to their child classes. Types can’t be declared as protected internal, so this applies only to members.

Public: a type or member of a type if declared as public is global in scope which can be accessed from anywhere.

Private Protected (Introducted in C# 7.3 Version): members declared as private protected in a class are accessible
only from the child classes that are defined in the same project. Types can’t be declared as private protected, so this
applies only to members.
To test access specifiers open a new CSharp Project of type “Console App.”, name the project as
“AccessDemo1” and re-name the solution as “MySolution”. By default the project comes with a class Program; write
the following code in it making it as public.

public class Program { //Case 1 (Accessing members of a class from same class)
private void Test1_Private() {
Console.WriteLine("Private Method");
}
internal void Test2_Internal() {
Console.WriteLine("Internal Method");

91
}
protected void Test3_Proteced() {
Console.WriteLine("Protected Method");
}
protected internal void Test4_ProtecedInternal() {
Console.WriteLine("Protected Internal Method");
}
public void Test5_Public() {
Console.WriteLine("Public Method");
}
public void Test6_PrivateProtected() {
Console.WriteLine("Public Method");
}
static void Main(string[] args) {
Program p = new Program();
p.Test1_Private(); p.Test2_Internal(); p.Test3_Proteced();
p.Test4_ProtecedInternal(); p.Test5_Public(); p.Test6_PrivateProtected();
}
}
Now add a new class Two.cs under the project and write the following:
class Two : Program { //Case 2 (Accessing members of a class from a child class in the same project)
static void Main() {
Two obj = new Two();
obj.Test2_Internal(); obj.Test3_Protected(); obj.Test4_ProtectedInternal();
obj.Test5_Public(); obj.Test6_PrivateProtected(); Console.ReadLine();
}
}
Now add another new class Three.cs in the project and write the following:
class Three { //Case 3 (Accessing members of a class from a non-child class in the same project)
static void Main() {
Program p = new Program();
p.Test2_Internal(); p.Test4_ProtectedInternal(); p.Test5_Public(); Console.ReadLine();
}
}
Now Add a new “Console App” project under “MySolution”, name it as “AccessDemo2”, rename the default
file Program.cs as Four.cs so that class name also changes to Four, add a reference to AccessDemo1 assembly from
its physical location to the new project and write the following code in the class Four:

class Four : AccessDemo1.Program { //Case 4 (Accessing members of a class from a child class in another project)
static void Main() {
Four obj = new Four();
obj.Test3_Protected(); obj.Test4_ProtectedInternal(); obj.Test5_Public(); Console.ReadLine();
}
}
Now add a new class under AccessDemo2 project, naming it as Five.cs and write the following:
using AccessDemo1

92
class Five { //Case 5(Accessing members of a class from a non-child class in another project)
static void Main() {
Program p = new Program();
p.Test5_Public(); Console.ReadLine();
}
}
Private Internal Protected Private Protected Public
Cases Protected Internal
Case 1: Same Class - Same Project Yes Yes Yes Yes Yes Yes
Case 2: Child Class - Same Project No Yes Yes Yes Yes Yes
Case 3: Non-Child Class - Same Project No Yes No No Yes Yes
Case 4: Child Class - Another Project No No Yes No Yes Yes
Case 5: Non-Child Class - Another Project No No No No No Yes

Language Interoperability
As discussed earlier the code written in 1 .NET Language can be consumed from any other .NET Languages and
we call this as Language Interoperability.
• VB is not a case-sensitive language.
• VB does not have any curly braces; the end of a block is represented with a matching End Stmt.
• VB does not have any semi colon terminators each statement must be in a new line.
• The extension of source files will be “.vb”.

To test this, add a new “Console App” project under “MySolution” choosing the language as Visual Basic and
name the project as “AccessDemo3”. By default the project comes with a file “Module1.vb”, so open solution
explorer, delete that file under project and add a new class naming it as “TestCS.vb”. Now add the reference of
“AccessDemo1” assembly to the current project choosing it from its physical location and write the following code
under the Class TestCS:
Imports AccessDemo1
Public Class TestCS : Inherits Program
Shared Sub Main()
Dim obj As New TestCS() ‘Creating a instance of a class in VB.Net Language
obj.Test3_Protected()
obj.Test4_ProtectedInternal()
obj.Test5_Public()
Console.ReadLine()
End Sub
End Class
Note: to run the class set both Startup Project and Startup Object properties also.
Consuming VB.Net Code in CSharp: Now to test consuming VB.Net code in CSharp, add a new project under
“MySolution”, choosing the language as VB, project type as "Class Library" and name the project as “AccessDemo4”.
A Class Library is a collection of types that can be consumed but not executed. After compilation the extension of
project’s assembly will be “.dll”.

In VB.Net language methods are divided into 2 categories like:


1. Functions (Value returning methods) 2. Sub-Routines (Non-value returning methods)

93
By default the project comes with a class Class1 within the file Class1.vb, write the below code in it:
Public Class Class1
Public Function SayHello(name As String) As String
Return "Hello " & name
End Function
Public Sub AddNums(x As Integer, y As Integer)
Console.WriteLine(x + y)
End Sub
Public Sub Math(a As Integer, b As Integer, ByRef c As Integer, ByRef d As Integer)
c=a+b
d=a*b
End Sub
End Class
Now to compile the project open solution explorer, right click on “AccessDemo4” project and select “Build”
option which compiles and generates an assembly “AccessDemo4.dll”.
Now add a new class under “AccessDemo2” project with the name “TestVB.cs”, add reference of
“AccessDemo4.dll” assembly from its physical location and write the following code under the class TestVB:

using AccessDemo4;
class TestVB {
static void Main() {
Class1 obj = new Class1(); obj.AddNums(100, 50);
int x = 0, y = 0; obj.Math(100, 25, ref x, ref y); Console.WriteLine(x + " " + y);
string str =obj.SayHello("Raju"); Console.WriteLine(str); Console.ReadLine();
}
}
Note: to run the class set both Startup Project and Startup Object properties also.

Q. How to restrict a class not to be accessible for any other class to consume?
Ans: This can be done by declaring all the class constructors as private.

Q. How to restrict a class not to be inherited for any other class?


Ans: This can be done by declaring class as sealed.

Q. How to restrict a class not to be accessible for any other class to consume by creating its instance?
Ans: This can be done by declaring all the class constructors as protected.

Destructor or Finalizer
Destructors are used to destruct objects (instances) of classes. A destructor is also a special method just like
a constructor, whereas constructors are called when instance of a class is created and destructors are called when
instance of a class is destroyed. Both of them will have the same name i.e. the name of class in which they are
defined, but to differentiate between each other we prefix destructor with a tilde (~) operator. For Example:

class Test {
Test() {
//Constructor

94
}
~Test() {
//Destructor
}
Remarks:
• Destructors cannot be defined in structs. They are only used with classes.
• A destructor does not take modifiers or have parameters.
• A class can only have one destructor and cannot be inherited or overloaded.
• Destructors cannot be called. They are invoked automatically.

The programmer has no control over when the destructor is called because this is determined by the garbage
collector; garbage collector calls the destructor in any of the following cases:
1. Called in the end of a programs execution and destroys all instances that are associated with the program.
2. In the middle of a programs execution also the garbage collector checks for instances that are no longer
being used by the application. If it considers an instance is eligible for destruction, it calls the destructor
and reclaims the memory used to store the instance.
3. It is possible to force garbage collector by calling GC.Collect() method to check for un-used instances and
reclaim the memory used to store those instances.

Note: we can force the garbage collector to do clean up by calling the GC.Collect method, but in most cases this
should be avoided because it may create performance issues, i.e. when the garbage collector comes into picture for
reclaiming memory of un-used instances, it will suspend the execution of programs.

To test a destructor add a new class DestDemo.cs and write the following:
class DestDemo {
public DestDemo() {
Console.WriteLine("Instance is created.");
}
~DestDemo() {
Console.WriteLine("Instance is destroyed.");
}
static void Main()
{
DestDemo d1 = new DestDemo();
DestDemo d2 = new DestDemo();
DestDemo d3 = new DestDemo();
//d1 = null; d3 = null; GC.Collect(); (Write all the 3 statements in the same line with comments).
Console.ReadLine();
}
}
Execute the above program by using Ctrl + F5 and watch the output of program, first it will call Constructor
for 3 times because 3 instances are created and then waits at ReadLine() statement to execute; now press enter key
to finish the execution of ReadLine(), immediately destructor gets called for 3 times because it is the end of programs
execution, so all 3 instances associated with the program are destroyed. This proves that destructor is called in the
end of a programs execution.

95
Now un-comment the commented code in Main method of above program and re-execute the program
again by using Ctrl + F5 to watch the difference in output, in this case 2 instances are destroyed before execution of
ReadLine() because we have marked them as un-used by assigning “null” and called Garbage Collector explicitly and
the third instance is destroyed in end of programs execution.

Destructors and Inheritance:


As we are aware that whenever a child class instance is created, child class constructor will call its parents
class constructor implicitly, same as this when a child class instance is destroyed it will also call its parent classes
destructor, but the difference is constructor are called in "Top to Bottom" hierarchy and destructor are called in
"Bottom to Top" hierarchy. To test this add a new class DestDemo2.cs and write the following code:

class DestDemo2 : DestDemo {


public DestDemo2() {
Console.WriteLine("Instance2 is created.");
}
~DestDemo2() {
Console.WriteLine("Instance2 is destroyed.");
}
static void Main() {
DestDemo2 obj = new DestDemo2();
Console.ReadLine();
}
}
Conclusion about Destructors: In general, C# does not require as much memory management; it is needed when
you develop with a language that does not target a runtime with garbage collection, for example CPP Language.
This is because the .NET Framework garbage collector implicitly manages the allocation and release of memory for
your instances. However, when your application encapsulates un-managed resources such as files, databases and
network connections, you should use destructors to free those resources.

Properties
A property is a member that provides a flexible mechanism to read, write, or compute the value of a private
field. Properties can be used as if they are public fields, but they are actually special methods called accessors.
Suppose a class is associated with any value and if we want to expose that value outside of the class, access to that
value can be given in 4 different ways:

I. By storing the value under a public field, access can be given to that value outside of the class, for Example:
public class Circle {
public double Radius = 12.34;
}

Now by creating the instance of above class we can get or set a value to the field as following:
class TestCircle {
static void Main() {
Circle c = new Circle();
double Radius = c.Radius; //Getting the old value of Radius

96
c.Radius = 56.78; //Setting a new value for Radius
}
}
Note: in this approach it will provide Read/Write access to the value i.e. anyone can get the old value of the field as
well as anyone can set with a new value for the field.

II. By storing the value under a private field also we can provide access to the value outside of the class by
defining a property on that field. The advantage in this approach is it can provide access to the value in 3
different ways:
I. Only get access (Read Only Property)
II. Only set access (Write Only Property)
III. Both get and set access (Read/Write Property)

Syntax to define a property:


[<modifiers>] <type> Name {
[ get { -Stmts } ] //Get Accessor
[ set { -Stmts } ] //Set Accessor
}


A property is one or two code blocks, representing a get accessor and/or a set accessor.

The code block for the get accessor is executed when the property is read and the body of the get accessor
resembles that of a method. It must return a value of the property type. The get accessor resembles a value
returning method without any parameters.
• The code block for the set accessor is executed when the property is assigned with a new value. The set
accessor resembles a non value returning method with parameter, i.e. it uses an implicit parameter called
“value”, whose type is the same type of the property.
• A property without a set accessor is considered as read-only. A property without a get accessor is
considered as write-only. A property that has both accessors is considered as read-write.
Remarks:
• Properties can be marked as public, private, protected, internal, or protected internal. These access
modifiers define how users of the class can access the property. The get and set accessors for the same
property may have different access modifiers. For example, the get may be public to allow read-only access
from outside the class, and the set may be private or protected.
• A property may be declared as a static property by using the static keyword. This makes the property
available to callers at any time, even if no instance of the class exists.
• A property may be marked as a virtual property by using the virtual keyword, which enables derived classes
to override the property behavior by using the override keyword. A property overriding a virtual property
can also be sealed, specifying that for derived classes it is no longer virtual.
• A property can be declared as abstract by using the abstract keyword, which means that there is no
implementation in the class, and derived classes must write their own implementation.
To test properties first add a new code file Cities.cs and write the following code:
namespace OOPSProject {
public enum Cities { Bengaluru, Chennai, Delhi, Hyderabad, Kolkata, Mumbai }
}
Now add a new class Customer.cs and write the following code:

97
public class Customer {
int _Custid; bool _Status; string _Name, _State; double _Balance; Cities _City;
public Customer(int Custid) {
_Custid = Custid; _Status = false; _Name = "John"; _Balance = 5000.00; _City = 0; _State = "Karnataka";
Country = "India";
}
public int Custid { //Read Only Property
get { return _Custid; }
}
public bool Status { //Read/Write Property
get { return _Status; } set { _Status = value; }
}
public string Name { //Read/Write Property with condition in set
get { return _Name; }
set { if(_Status) { _Name = value; } }
}
public double Balance { //Read/Write Property with condition in get & set
get { if(_Status) { return _Balance; } return 0; }
set { if (_Status) { if(value >= 500) { _Balance = value; } } }
}
public Cities City { //Read/Write Enumerated Property
get { return _City; }
set { if (_Status) { _City = value; } }
}
public string State { //Read/Write property with different scope to each accessor (2.0)
get { return _State; }
protected set { if (_Status) { _State = value; } }
}
public string Country { //Auto-Implemented or Automatic Property (3.0)
get; private set;
}
public string Continent { get; } = "Asia"; //Auto-Property Initializer (6.0)
}
Note: The contextual keyword value is used in the set accessor in ordinary property declarations. It is similar to an
input parameter of a method. The word value references the value that client code is attempting to assign to the
property.
Enumerated Property:
It is a property that provides with a set of constants to choose from, for example BackgroundColor property
of the Console class that provides with a list of constant colors to choose from, under an enum ConsoleColor. E.g.:
Console.BackgroundColor = ConsoleColor.Blue;

An enum is a distinct type that consists of a set of named constants called the enumerator list. Usually it is
best to define an enum directly within a namespace so that all classes in the namespace can access it with equal
convenience. However, an enum can also be nested within a class or structure.

Syntax to define an enum:

98
[<modifiers>] enum <Name> { <list of constant values> }
E.g.: public enum Days { Monday, Tuesday, Wednesday, Thursday, Friday }

By default, the first value is represented with an index 0, and the value of each successive enumerator is
increased by 1. For example, in the above enumeration, Monday is 0, Tuesday is 1, Wednesday is 2, and so forth.
To define an Enumerated Property adopt the following process:
Step 1: define an enum with the list of constants we want to provide for the property to choose.
E.g.: public enum Days { Monday, Tuesday, Wednesday, Thursday, Friday };
Step 2: declare a field of type enum on which we want to define a property.
E.g.: Days _Day = 0; or Days _Day = Days.Monday; or Days _Day = (Days)0;
Step 3: now define a property on the enum field for providing access to its values.
public Days Day {
get { return _Day; }
set { _Day = value; }
}
Auto-Implemented properties:
In C# 3.0 and later, auto-implemented properties make property-declaration more concise when no
additional logic is required in the property accessors. E.g.: Country property in our Customer class, but up to CSharp
5.0 it is important to remember that auto-implemented properties must contain both get and set blocks either with
the same access modifier or different also whereas from CSharp 6.0 it’s not mandatory because of a new feature
called “Auto Property Initializer”, which allows to initialize a property at declaration time. In our Customer class the
Country property we have defined can be implemented as following also:
E.g.: public string Country { get; } = "India";
To consume the properties we have defined above add a new class TestCustomer.cs and write the following:
class TestCustomer {
static void Main() {
Customer obj = new Customer(101);
Console.WriteLine("Custid: " + obj.Custid);
//obj.Custid = 102; //Can't be assigned to as property is read only

Console.WriteLine("Old Name: " + obj.Name);


obj.Name = "John Smith"; Console.WriteLine("New Name: " + obj.Name);
if(obj.Status) { Console.WriteLine("Status: Active"); }
else {Console.WriteLine("Status: In-Active"); }
Console.WriteLine("Current Balance: " + obj.Balance); //Prints Balance as 0, because status is in-active

obj.Status = true; //Activating the status again


if(obj.Status) { Console.WriteLine("Status: Active"); }
else {Console.WriteLine("Status: In-Active"); }
Console.WriteLine("Current Balance: " + obj.Balance); //Prints actual Balance, as status is active again

obj.Balance -= 4600; //Transaction fails


Console.WriteLine("Balance when transaction failed: " + obj.Balance); //Prints old balance value only
obj.Balance -= 4500; //Transaction succeeds
Console.WriteLine("Balance when transaction succeeded " + obj.Balance); //Prints new balance value

99
Console.WriteLine("Current City: " + obj.City);
obj.City = Cities.Hyderabad; Console.WriteLine("Modified City: " + obj.City);

Console.WriteLine("Current State: " + obj.State);


//obj.State = "AP"; //Can't be assigned with a value, as current class is not a child class of Customer

Console.WriteLine("Country: " + obj.Country); //Auto-Implemented Property


Console.WriteLine("Continent: " + obj.Continent); //Auto-Property Initializer
Console.ReadLine();
}
}

Object Initializers (Introduced in C# 3.0)


Object initializers let you assign values to any accessible properties of an instance at creation time without
having to explicitly invoke a parameterized constructor. You can use object initializers to initialize type objects in a
declarative manner without explicitly invoking a constructor for the type. Object Initializers will use the default
constructor for initializing properties. To test these add a new CodeFile naming it as TestStudent.cs and write the
following code in it:

using System;
namespace OOPSProject {
public class Student {
int? _Id, _Class; string _Name; float? _Marks, _Fees;
public int? Id { get { return _Id; } set { _Id = value; } }
public int? Class { get { return _Class; } set { _Class = value; } }
public string Name { get { return _Name; } set { _Name = value; } }
public float? Marks { get { return _Marks; } set { _Marks = value; } }
public float? Fees { get { return _Fees; } set { _Fees = value; } }
public override string ToString() {
return "Id: " + _Id + "\nName: " + _Name + "\nClass: " + _Class + "\nMarks: " + _Marks + "\nFees: " + _Fees;
}
}
class TestStudent {
static void Main() {
Student s1 = new Student { Id = 101, Name = "Raju", Class = 10, Marks = 550.00f, Fees = 5000.00f };
Student s2 = new Student { Id = 102, Name = "Venkat", Class = 10 };
Student s3 = new Student { Id = 103, Name = "Suresh", Marks = 575.00f };
Console.WriteLine(s1); Console.WriteLine(s2); Console.WriteLine(s3); Console.ReadLine();
}
}
}

Indexers
Indexers allow instances of a class or struct to be indexed just like arrays. Indexers resemble properties
except that their accessors take parameters. Indexers are syntactic conveniences that enable you to create a class
or struct that client applications can access just as an array. Defining an indexer allows you to create classes that act

100
like "virtual arrays." Instances of that class or structure can be accessed using the [] array access operator. Defining
an indexer in C# is similar to defining operator [] in C++, but is considerably more flexible. For classes or structure
that encapsulate array or collection - like functionality, defining an indexer allows the users of that class or structure
to use the array syntax to access the class or structure. An indexer doesn't have a specific name like a property it is
defined by using “this” keyword.

Syntax to define Indexer:


[<modifiers>] <type> this[<Parameter List>] {
[ get { -Stmts } ] //Get Accessor
[ set { -Stmts } ] //Set Accessor
}

Indexers Overview:
• “this” keyword is used to define the indexers.
• The out and ref keyword are not allowed on parameters.
• A get accessor returns a value. A set accessor assigns a value.
• The value keyword is only used to define the value being assigned by the set indexer.
• Indexers do not have to be indexed by integer value; it is up to you how to define the look-up mechanism.
• Indexers can be overloaded.
• Indexers can't be defined as static.
• Indexers can have more than one formal parameter, for example, accessing a two-dimensional array.
To test indexers add a CodeFile under the project naming it as TestEmployee.cs and write the below code in it:
using System;
namespace OOPSProject {
public class Employee {
int _Eno; bool _Status; double _Salary; string _Name, _Job;
public Employee(int Eno) {
_Eno = Eno; _Status = true; _Name = "Scott"; _Job = "Manager"; _Salary = 25000.00;
}
public object this[int Index] {
get {
if (Index == 1) { return _Eno; }
else if (Index == 2) { return _Name; }
else if (Index == 3) { return _Job; }
else if (Index == 4) { return _Salary; }
else if (Index == 5) { return _Status; }
else { return null; }
}
set {
if (Index == 2) { _Name = (string)value; }
else if (Index == 3) { _Job = (string)value; }
else if (Index == 4) { _Salary = (double)value; }
else if (Index == 5) { _Status = (bool)value; }
}
}

101
public object this[char Index] {
get {
if (Char.ToUpper(Index) == 'A') { return _Eno; }
else if (Char.ToUpper(Index) == 'B') { return _Name; }
else if (Char.ToUpper(Index) == 'C') { return _Job; }
else if (Char.ToUpper(Index) == 'D') { return _Salary; }
else if (Char.ToUpper(Index) == 'E') { return _Status; }
else { return null; }
}
set {
if (Char.ToLower(Index) == 'b') { _Name = (string)value; }
else if (Char.ToLower(Index) == 'c') { _Job = (string)value; }
else if (Char.ToLower(Index) == 'd') { _Salary = (double)value; }
else if (Char.ToLower(Index) == 'e') { _Status = (bool)value; }
}
}
}
class TestEmployee {
static void Main() {
Employee Emp = new Employee(1001);
Console.WriteLine("Employee No: " + Emp[1]); Console.WriteLine("Employee Name: " + Emp[2]);
Console.WriteLine("Employee Job: " + Emp[3]); Console.WriteLine("Employee Salary: " + Emp[4]);
Console.WriteLine("Employee Status: " + Emp[5] + "\n");

Emp[3] = "Sr. Manager"; Emp['D'] = 30000.00;


Console.WriteLine("Employee No: " + Emp['A']); Console.WriteLine("Employee Name: " + Emp['b']);
Console.WriteLine("Employee Job: " + Emp['C']); Console.WriteLine("Employee Salary: " + Emp['d']);
Console.WriteLine("Employee Status: " + Emp['E']); Console.ReadLine();
}
}
}

Deconstructor
These are newly introduced in C# 7.0 which can also be used to provide access to the values or expose the
values associated with a class to the outside environment, apart from public fields, properties and indexers.
Deconstructor is a special method with the name “Deconstruct” that is defined under the class to expose (Read Only)
the attributes of a class and this will be defined with a code that is reverse to a constructor.

To understand deconstructors, add a code file in our project naming it as “TestTeacher.cs” and write the
below code in it:

using System;
namespace OOPSProject {
public class Teacher {
int Id;
string Name, Subject, Designation;

102
double Salary;
public Teacher(int Id, string Name, string Subject, string Designation, Double Salary) {
this.Id = Id;
this.Name = Name;
this.Subject = Subject;
this.Designation = Designation;
this.Salary = Salary;
}
public void Deconstruct(out int Id, out string Name, out string Subject, out string Designation, out double Salary)
{
Id = this.Id;
Name = this.Name;
Subject = this.Subject;
Designation = this.Designation;
Salary = this.Salary;
}
}

class TestTeacher {
static void Main() {
Teacher obj = new Teacher(1005, "Suresh", "English", "Lecturer", 25000.00);
(int Id, string Name, string Subject, string Designation, double Salary) = obj;
Console.WriteLine("Teacher Id: " +Id);
Console.WriteLine("Teacher Name: " + Name);
Console.WriteLine("Teacher Subject: " + Subject);
Console.WriteLine("Teacher Designation: " + Designation);
Console.WriteLine("Teacher Salary: " + Salary);
Console.ReadLine();
}
}
}
In the above case “Deconstruct” (name cannot be changed) is a special method which will expose the
attributes of teacher class. We can capture the values exposed by “Deconstructors” by using tuples, through the
instance of class we have created.
E.g: (int Id, string Name, string Subject, string Designation, double Salary) = obj;
The above statement can be implemented as following also:
E.g: (var Id, var Name, var Subject, var Designation, var Salary) = obj;
The above statement can be implemented as following also:
E.g: var (Id, Name, Subject, Designation, Salary) = obj;
Note: Deconstructors will provide read-only access to the attributes of a class.

We can also overload Deconstructors to access particular values from the list of attributes and to test that
add the following deconstructor in the Teacher class.

public void Deconstruct(out int Id, out string Name, out double Salary) {
Id = _Id; Name = _Name; Salary = _Salary;

103
}
Now we can capture only those 3 values and to test that write the following code in the “Main()” method
of “TestTeacher” class just above the “ReadLine()” method.

var (Id1, Name1, Salary1) = obj;


Console.WriteLine("Teacher Id: " + Id1);
Console.WriteLine("Teacher Name: " + Name1);
Console.WriteLine("Teacher Salary: " + Salary1);

Without OverLoading the Deconstructors also we can access required attribute values by just putting "_" at
the place whose values we don't want to access, and to test this Add the following code in the “Main()” method of
“TestTeacher” class just above the “ReadLine()” method.

var (Id2, Name2, Subject2, _, _) = obj;


Console.WriteLine("Teacher Id: " + Id2);
Console.WriteLine("Teacher Name: " + Name2);
Console.WriteLine("Teacher Subject: " + Subject2);

var (Id3, _, _, Designation3, Salary3) = obj;


Console.WriteLine("Teacher Id: " + Id3);
Console.WriteLine("Teacher Designation: " + Designation3);
Console.WriteLine("Teacher Salary: " + Salary3);

var (Id4, _, Subject4, _, Salary4) = obj;


Console.WriteLine("Teacher Id: " + Id4);
Console.WriteLine("Teacher Subject: " + Subject4);
Console.WriteLine("Teacher Salary: " + Salary4);
Exceptions and Exception Handling
In the development of an application we will be coming across 2 different types of errors, like:
• Compile time errors.
• Runtime errors.

Errors which occur in a program due to syntactical mistakes at the time of program compilation are known
as compile time errors and these are not considered to be dangerous.
Errors which occur in a program while the execution of a program is taking place are known as runtime
errors, which can occur due to various reasons like wrong implementation of logic, wrong input supplied to the
program, missing of required resources etc. Runtime errors are dangerous because when they occur under the
program, the program terminates abnormally at the same line where the error got occurred without executing the
next lines of code. To test this, add a new class naming it as ExceptionDemo.cs and write the following code:
class ExceptionDemo {
static void Main() {
Console.Write("Enter 1st number: " ); int x = int.Parse(Console.ReadLine());
Console.Write("Enter 2nd number: " ); int y = int.Parse(Console.ReadLine());
int z = x / y; Console.WriteLine("The result of division is: " + z); Console.WriteLine("End of the Program.");
}

104
}
Execute the above program by using Ctrl + F5, and here there are chances of getting few runtime errors
under the program, to check them enter the value for y as ‘0’ or enter character input for x or y values, and in both
cases when an error got occurred program gets terminated abnormal on the same line where error got occurred.

Exception: In C#, errors in the program at run time are caused through the program by using a mechanism called
Exceptions. Exceptions are classes derived from class Exception of System namespace. Exceptions can be thrown by
the .NET Framework CLR (Common Language Runtime) when basic operations fail or by code in a program. Throwing
an exception involves creating an instance of an Exception-derived class, and then throwing that instance by using
the throw keyword. There are so many Exception classes under the Framework Class Library where each class is
defined representing a different type of error that occurs under the program, for example: FormatException,
NullReferenceException, IndexOutOfRangeException, ArithmeticException etc.

Exceptions are basically 2 types like SystemExceptions and ApplicationExceptions. System Exceptions are
pre-defined exceptions that are fatal errors which occur on some pre-defined error conditions like DivideByZero,
FormatException, NullReferenceException etc. ApplicationExceptions are non-fatal errors i.e. these are error that
are caused by the programs explicitly. Whatever the exception it is every class is a sub class of class Exception only
and the hierarchy of these exception classes will be as following:
➢ Exception
➢ SystemException
➢ FormatException
➢ NullReferenceException
➢ IndexOutOfRangeException
➢ ArithmeticException
➢ DivideByZeroException
➢ OverflowException
➢ ApplicationException
Exception Handling: It is a process of stopping the abnormal termination of a program whenever a runtime error
occurs under the program; if exceptions are handled under the program we will be having the following benefits:

1. As abnormal termination is stopped, statements that are not related with the error can be still executed.
2. We can also take any corrective actions which can resolve the problems that may occur due to the errors.
3. We can display user friendly error messages to end users in place of pre-defined error messages.

How to handle an Exception: to handle an exception we need to enclose the code of the program under some
special blocks known as try and catch blocks which should be used as following:

try {
-Statement’s where there is a chance of getting runtime errors.
-Statement’s which should not execute when the error occurs.
}
catch(<Exception Class Name> [<Variable>]) {
-Statement’s which should execute only when the error occurs.
}
[---<multiple catch blocks if required>---]

105
To test handling exceptions add a new class TryCatchDemo.cs and write the following code:

class TryCatchDemo {
static void Main() {
try {
Console.Write("Enter 1st number: " ); int x = int.Parse(Console.ReadLine();
Console.Write("Enter 2nd number: " ); int y = int.Parse(Console.ReadLine());
int z = x / y; Console.WriteLine(“The result of division is: “ + z);
}
catch(DivideByZeroException) { Console.WriteLine("Divisor value should not be zero."); }
catch(FormatException) { Console.WriteLine("Input values must be numeric."); }
catch(Exception ex) { Console.WriteLine(ex.Message); }
Console.WriteLine("End of the program.");
}
}

If we enclose the code under try and catch blocks the execution of program will take place as following:
• If all the statements under try block are successfully executed (i.e. no error in the program), from the last
statement of try the control directly jumps to the first statement which is present after all the catch blocks.
• If any statement under try causes an error from that line, without executing any other lines of code in try,
control directly jumps to catch blocks searching for a catch block to handle the error:
• If a catch block is available that can handle the exception then exceptions are caught by that catch
block, executes the code inside of that catch block and from there again jumps to the first
statement which is present after all the catch blocks.
• If a catch block is not available to handle that exception which got occurred, abnormal termination
takes place again on that line.
Note: Message is a property under the Exception class which gets the error message associated with the exception
that got occurred under the program, this property was defined as virtual under the class Exception and overridden
under all the child classes of class Exception as per their requirement, that is the reason why when we call
“ex.Message” under the last catch block, even if “ex” is the reference of parent class, it will get the error message
that is associated with the child exception class but not of itself because we have already learnt in overriding that
“parent’s reference which is created by using child classes instance will call child classes overridden members” i.e.
nothing but dynamic polymorphism.

Finally Block: this is another block of code that can be paired with try along with catch or without catch also and the
specialty of this block is code written under this block gets executed at any cost i.e. when an exception got occurred
under the program or an exception did not occur under the program. All statements under try gets executed only
when there is no exception under the program and statements under catch block will be executed only when there
is exception under the program whereas code under finally block gets executed in both the cases. To test finally
block add a new class FinallyDemo.cs and write the following code:

class FinallyDemo {
static void Main() {
try {
Console.Write("Enter 1st number: " ); int x = int.Parse(Console.ReadLine());
Console.Write("Enter 2nd number: " ); int y = int.Parse(Console.ReadLine());

106
if (y == 1) { return; } int z = x / y; Console.WriteLine(“The result of division is: “ + z);
}
catch(Exception ex) { Console.WriteLine(ex.Message); }
finally { Console.WriteLine("Finally block executed."); }
Console.WriteLine("End of the program.");
} //End of the method
}
Execute the above program for 2 times, first time by giving input which doesn’t cause any error and second
time by giving the input which causes an error and check the output where in both the cases finally block is executed.
In both the cases not only finally block along with it “End of the program.” statement also gets executed,
now test the program for the third time by giving the divisor value i.e. value to y as 1, so that the if condition in the
try block gets satisfied and return statement gets executed. As we are aware that return is a jump statement which
jumps out of the method in execution, but in this case it will jump out only after executing the finally block of the
method because once the control enters into try we cannot stop the execution of finally block.

Note: try, catch and finally blocks can be used in 3 different combinations like:
I. try and catch: in this case exceptions that occur in the program are caught by the catch block so abnormal
termination will not take place.
II. try, catch and finally: in this case behavior will be same as above but along with it finally block keeps
executing in any situation.
III. try and finally: in this case exceptions that occur in the program are not caught because there is no catch
block so abnormal termination will take place but still the code under finally block gets executed.

Application Exceptions: these are non-fatal application errors i.e. these are errors that are caused by the programs
explicitly. Application exceptions are generally raised by programmers under their programs basing on their own
error conditions, for example in a division program we don’t want the divisor value to be an odd number. If a
programmer wants to raise an exception explicitly under his program he needs to do 2 things under the program.
1. Create the instance of any exception class.
2. Throw that instance by using throw statement. E.g.: throw <instance of exception class>

While creating an Exception class instance to throw explicitly we are provided with different options in choosing
which exception class instance has to be created to throw, like:
1. We can create instance of a pre-defined class i.e. ApplicationException by passing the error message that
has to be displayed when the error got occurred as a parameter to the class constructor and then throw
that instance.
E.g. ApplicationException ex = new ApplicationException (“<error message>”);
throw ex;
or
throw new ApplicationException (“<error message>”);
2. We can also define our own exception class, create instance of that class and throw it when required. If we
want to define a new exception class we need to follow the below process:
I. Define a new class inheriting from any pre-defined Exception class (but ApplicationException is
preferred choice as we are dealing with application exceptions) so that the new class also is an
exception.
II. Override the Message property inherited from parent by providing the required error message.

107
To test this first add a new class under the project naming it DivideByOddNoException.cs and write the following:
public class DivideByOddNoException : ApplicationException {
public override string Message {
get { return "Attempted to divide by odd number."; }
}
}

Now add a new class ThrowDemo.cs and write the following code:
class ThrowDemo {
static void Main() {
Console.Write("Enter 1st number: " ); int x = int.Parse(Console.ReadLine());
Console.Write("Enter 2nd number: " ); int y = int.Parse(Console.ReadLine());
if(y % 2 > 0) {
throw new ApplicationException(“Divisor value should not be an odd number.”);
//throw new DivideByOddNoException();
}
int z = x / y; Console.WriteLine(“The result of division is: “ + z);
Console.WriteLine("End of the program.");
}
}
Test the above program for the first time by giving the divisor value as an odd number and now
ApplicationException will raise and displays the error message “Divisor value should not be an odd number.”. Now
comment the first throw statement and uncomment the second throw statement so that when the divisor value is
an odd number DivideByOddNoException will raise and displays the error message “Attempted to divide by odd
number.”.
Delegates
Delegate is a type which holds the method(s) reference in an object. It is also referred to as a type safe
function pointer. Delegates are roughly similar to function pointers in C++; however, delegates are type-safe and
secure. A delegate instance can encapsulate a static or a non-static method also and call that method for execution.
Effective use of a delegate improves the performance of applications.

Methods can be called in 2 different ways in C#, those are:


1. Using instance of a class if it is non-static and name of the class if it is static.
2. Using a delegate (either static or non-static).

To call a method by using delegate we need to adopt the following process:


1. Define a delegate.
2. Instantiate the delegate.
3. Call the delegate by passing required parameter values.

Defining a Delegate:
[<modifiers>] delegate void|<type> Name(<Parameter List>)

108
Note: while defining a delegate you should follow the same signature of the method i.e. parameters of delegate
should be same as the parameters of method and return types of delegate should be same as the return types of
method we want to call by using the delegate.

public void AddNums(int x, int y) {


Console.WriteLine(x + y);
}
public delegate void AddDel(int x, int y);

public static string SayHello(string name) {


return “Hello “ + name;
}
public delegate string SayDel(string name);

Instantiate the delegate: In this process we create the instance of delegate and bind the method with delegate.
AddDel ad = new AddDel(AddNums); or AddDel ad = AddNums;
SayDel sd = new SayDel(SayHello); or SayDel sd = SayHello;

Calling the delegate: Call the delegate by passing required parameter values, so that the method which is bound
with delegate gets executed.
ad(100, 50); string str = sd(“Raju”);

Where to define a delegate: Delegates can be defined either with in a class or with in a namespace also just like we
define other types.
Add a code file under the project naming it as Delegates.cs and write the following code:
namespace OOPSProject {
public delegate void MathDelegate(int x, int y);
public delegate string WishDelegate(string name);
public delegate void CalculatorDelegate(int a, int b, int c);
}
Add a new class DelDemo1.cs under the project and write the following code:
class DelDemo1 {
public void AddNums(int x, int y, int z) {
Console.WriteLine(x + y + z);
}
public static string SayHello(string name) {
return "Hello " + name + “, good morning.”;
}
static void Main() {
DelDemo1 obj = new DelDemo1();
CalculatorDelegate cd = obj.AddNums; (or) CalculatorDelegate cd = new CalculatorDelegate(obj.AddNums);
cd(100, 50, 25); cd(123, 456, 789); cd(396, 224, 156);

WishDelegate wd = DelDemo1.SayHello; (or) WishDelegate wd = WishDelegate(DelDemo1.SayHello);


Console.WriteLine(wd("Raju")); Console.WriteLine(wd("Naresh")); Console.WriteLine(wd("Praveen"));
Console.ReadLine();

109
}
}
Multicast Delegate: It is a delegate which holds the reference of more than one method. Multicast delegates must
contain only methods that return void. If we want to call multiple methods using a single delegate all the methods
should have the same Parameter types. To test this, add a new class DelDemo2.cs under the project and write the
following code:

class DelDemo2 {
public void Add(int x, int y) {
Console.WriteLine("Add: " + (x + y));
}
public void Sub(int x, int y) {
Console.WriteLine("Sub: " + (x - y));
}
public void Mul(int x, int y) {
Console.WriteLine("Mul: " + (x * y));
}
public void Div(int x, int y) {
Console.WriteLine("Div: " + (x / y));
}
static void Main() {
DelDemo2 obj = new DelDemo2();
MathDelegate md = obj.Add; md += obj.Sub; md += obj.Mul; md += obj.Div;
md(100, 50); Console.WriteLine(); md(575, 25); Console.WriteLine(); md -= obj.Mul; md(678, 28);
Console.ReadLine();
}
}
Anonymous Methods (Introduced in CSharp 2.0):
In versions of C# before 2.0, the only way to instantiate a delegate was to use named methods. C# 2.0
introduced anonymous methods which provide a technique to pass a code block as a delegate parameter.
Anonymous methods are basically methods without a name. An anonymous method is inline unnamed method in
the code. It is created using the delegate keyword and doesn’t require modifiers, name and return type. Hence we
can say an anonymous method has only body without name, return type and optional parameters. An anonymous
method behaves like a regular method and allows us to write inline code in place of explicitly named methods. To
test this, add a new class DelDemo3.cs and write the following code:

class DelDemo3 {
static void Main() {
WishDelegate wd = delegate(string name) {
return "Hello Mr./Ms./Mrs. " + name + " have a nice day.";
};
CalculatorDelegate cd = delegate(int a, int b, int c) {
Console.WriteLine(a * b * c);
};
Console.WriteLine(wd("Raju")); Console.WriteLine(wd("Naresh")); Console.WriteLine(wd("Praveen"));
cd(10, 20, 30); cd(40, 50, 60); cd(70, 80, 90);

110
Console.ReadLine();
}
}
Lambda Expression (Introduced in CSharp 3.0):
While Anonymous Methods were a new feature in 2.0, Lambda Expressions are simply an improvement to
syntax when using Anonymous method. Lambda Operator “=>” was introduced so that there is no longer a need to
use the delegate keyword, or provide the type of the parameter. The type can usually be inferred by compiler from
usage. To test this, add a new class DelDemo4.cs and write the following code:
class DelDemo4 {
static void Main() {
WishDelegate wd = name => {
return "Hello Mr./Ms./Mrs. " + name + " have a nice day.";
};
Console.WriteLine(wd("Raju")); Console.WriteLine(wd("Naresh")); Console.WriteLine(wd("Praveen"));

CalculatorDelegate cd = (a, b, c) => {


Console.WriteLine(a * b * c);
};
cd(10, 20, 30); cd(40, 50, 60); cd(70, 80, 90);
Console.ReadLine();
}
}
Expression Bodied Members (Introduced in CSharp 6.0 & 7.0):
Expression body definitions let you provide a member's implementation in a very concise, readable form.
You can use an expression body definition whenever the logic for any supported member consists of a single
expression. An expression body definition has the following general syntax:
member => expression;
To test this, add a new class DelDemo5.cs and write the following code:
class DelDemo5 {
static void Main() {
WishDelegate sd = name => "Hello Mr./Ms./Mrs. " + name + " have a nice day.";
CalculatorDelegate cd = (a, b, c) => Console.WriteLine(a * b * c);
Console.WriteLine(wd("Raju")); Console.WriteLine(wd("Naresh")); Console.WriteLine(wd("Praveen"));
cd(10, 20, 30); cd(40, 50, 60); cd(70, 80, 90); Console.ReadLine(); Console.ReadLine();
}
}
Why would we need to write a method without a name is convenience i.e. it's a shorthand that allows you
to write a method in the same place you are going to use it. Especially useful in places where a method is being used
only once and the method definition are short. It saves you the effort of declaring and writing a separate method to
the containing class. Benefits are like Reduced typing, i.e. no need to specify the name of the method, its return
type, and its access modifier as well as when reading the code you don't need to look elsewhere for the method
definition. Anonymous methods should be short; a complex definition makes calling code difficult to read.
Support for expression body definitions was introduced for methods and read-only properties in C# 6 and
was expanded in C# 7.0. Expression body definitions can be used with the type members listed in following table:
Member Supported as of...

111
Method C# 6
Read-only property C# 6
Property C# 7.0
Constructor C# 7.0
Finalizer C# 7.0
Indexer C# 7.0
For example, below is a class defined with out using expression bodied members:
public class Circle {
double _Radius; const float _Pi = 3.14f;
public Circle(double Radius) {
_Radius = Radius;
}
~Circle() {
Console.WriteLine("Instance is destroyed.");
}
public float Pi {
get { return _Pi; }
}
public double Radius {
get { return _Radius; } set { _Radius = value; }
}
public double GetArea() {
return _Pi * _Radius * _Radius;
}
public double GetPerimeter() {
return 2 * _Pi * _Radius;
}
}
Above class cen be defined as following by using expression bodied members:
public class Circle {
double _Radius;
const float _Pi = 3.14f;
public Circle(double Radius) => _Radius = Radius; //C# 7.0
~Circle() => Console.WriteLine("Instance is destroyed."); //C# 7.0
public float Pi => _Pi; //C# 6.0
public double Radius //C# 7.0
{
get => _Radius;
set => _Radius = value;
}
public double GetArea() => _Pi * _Radius * _Radius; //C# 6.0
public double GetPerimeter() => 2 * _Pi * _Radius; //C# 6.0
}
Anonymous Types (Introduced in C# 3.0):

112
Anonymous type, as the name suggests, is a type that doesn't have any name. C# allows you to create an
instance with the new keyword without defining a class. The implicitly typed variable - “var” or “dynamic” is used to
hold the reference of anonymous types.
var EmpType = new { Id = 1001, Name = "Raju", Job = "Manager", Salary = 25000.00, Status = true };

In the above example, “EmpType” is an instance of the anonymous type which is created by using the new
keyword and object initializer syntax. It includes 5 properties of different data types. An anonymous type is a
temporary data type that is inferred based on the data that you include in an object initializer. Properties of
anonymous types will be read-only properties so you cannot change their values.

Notice that the compiler applies the appropriate type to each property based on the value assigned. For
example Id is of integer type, Name and Job are of string type, Salary is of double type and Status is of boolean type.
Internally, the compiler automatically generates the new type for anonymous types. You can check that by calling
GetType method on an anonymous type instance which will return the following value:
<>f__AnonymousType0`5[System.Int32,System.String,System.String,System.Double,System.Boolean]

Remember that Anonymous Types are derived from the Object class and it is a sealed class and all the
properties are created as read only properties. An anonymous type will always be local to the method where it is
defined. Usually, you cannot pass an anonymous type to another method; however, you can pass it to a method that
accepts a parameter of dynamic type. Anonymous types can be nested i.e. an anonymous type can have another
anonymous type as a property.

Points to Remember:
• Anonymous type can be defined using the new keyword and object initializer syntax.
• The implicitly typed variable - “var” or “dynamic” keyword, is used to hold an anonymous type.
• Anonymous type is a reference type and all the properties are read-only.
• The scope of an anonymous type is local to the method where it is defined.

To test anonymous types add a new Code File under the project naming it as “TestAnonymousTypes.cs”
and write the following code in it:
using System;
namespace OOPSProject {
class Printer {
public static void Print(dynamic d) {
Console.WriteLine("Employee No: " + d.Eno);
Console.WriteLine("Employee Name: " + d.Name);
Console.WriteLine("Employee Job: " + d.Job);
Console.WriteLine("Employee Salary: " + d.Salary);
Console.WriteLine("Employee Status: " + d.Status);
Console.WriteLine("Department No: " + d.Dept.Did);
Console.WriteLine("Department Name: " + d.Dept.Dname);
Console.WriteLine("Department Location: " + d.Dept.Location);
}
}
class TestAnonymousTypes {
static void Main() {

113
var EmpType = new { Eno = 1005, Name = "Scott", Job = "Manager", Salary = 25000.00, Status = true,
Dept = new { Did = 30, Dname = "Sales", Location = "Hyderabad" } };
Printer.Print(EmpType); Console.ReadLine();
}
}
}
Partial Types/Partial Classes (Introduced in CSharp 2.0):
It is possible to split the definition of a class or struct or an interface over two or more source files. Each
source file contains a section of the type definition, and all parts are combined when the application is compiled.
There are several situations when splitting a class definition is desirable like:
• When working on large projects, spreading a type over separate files enables multiple programmers to work
on it at the same time.
• Visual Studio uses these partial classes for auto generation of source code in the development of Windows
Forms Applications, Web Applications, and Web Services and so on.

Points to Remember:
• The partial keyword indicates that other parts of the class, struct, or interface can be defined in the
namespace.
• All the parts must use the partial keyword.
• All the parts must be available at compile time to form the final type.
• All the parts must have the same accessibility, such as public or internal.
• If any part is declared abstract, then the whole type is considered abstract.
• If any part is declared sealed, then the whole type is considered sealed.
• If any part declares a base type, then the whole type inherits that class.
• Parts can specify different base interfaces, and the final type implements all the interfaces listed by all the
partial declarations.
• Any class, struct, or interface members declared in a partial definition are available to all the other
parts.
• The final type is the combination of all the parts at compile time.
• The partial modifier is not available on delegate or enumeration declarations.

To test partial classes add 2 new code files under the project Part1.cs and Part2.cs and write the following code:

using System;
namespace OOPSProject {
partial class Parts {
public void Method1() {
Console.WriteLine("Method 1");
}

114
public void Method2() {
Console.WriteLine("Method 2");
}
}
}
using System;
namespace OOPSProject {
partial class Parts {
public void Method3() {
Console.WriteLine("Method 3");
}
public void Method4() {
Console.WriteLine("Method 4");
}
}
}
Now to test the above partial class, add a new class TestParts.cs under the project and write the following code:
class TestParts {
static void Main() {
Parts p = new Parts();
p.Method1(); p.Method2(); p.Method3(); p.Method4(); Console.ReadLine();
}
}
Partial Methods (Introduced in C# 3.0):
A partial class or struct may contain a partial method. One part of the type contains the signature of the
method and an optional implementation may be defined in the same part or another part. If the implementation is
not supplied, then the method and all calls to the method are removed at compile time.
Partial methods enable the implementer of one part of a type to define a method and the implementer of
the other part of the type can decide whether to implement the method or not. If the method is not implemented,
then the compiler removes the method signature and all calls to the method. The calls to the method, including any
results that would occur from evaluation of arguments in the calls, have no effect at run time. Therefore, any code
in the partial type can freely use a partial method, even if the implementation is not supplied, no compile-time or
run-time errors will result if the method is called but not implemented.
Partial methods are especially useful as a way to customize generated code. They allow for a method name
and signature to be reserved, so that generated code can call the method but the developer can decide whether to
implement the method or not.
A partial method consists of two parts: the declaration, and the implementation. These may be in separate
parts of a partial type, or in the same part. If there is no implementation for the declaration, then the compiler
removes both the defining declaration and all calls to the method.

partial void TestMethod(); // Declaration in file1.cs


partial void TestMethod() { // Implementation in file2.cs
//Method Body
}
There are several rules to follow with partial types and partial methods as defined by Microsoft and those rules
are listed below:

115
• Partial methods are indicated by the partial modifier and can be declared within partial classes only.
• Partial methods must be private and must return void.
• Partial methods do not always have an implementation and can also be declared as static.
• Partial methods can have arguments including ref but not out.
• You cannot make a delegate to a partial method.

To test partial methods add 2 new code files Test1.cs and Test2.cs under the project and write the following code:

using System;
namespace OOPSProject {
partial class Test {
partial void Method1(); //Partial method declaration
public void Method2() {
Console.WriteLine("Method 2.");
Method1(); //Calling Partial Method
}
}
}
using System;
namespace OOPSProject {
partial class Test {
partial void Method1() { //Partial method implementation
Console.WriteLine("Method 1.");
}
static void Main() {
Test obj = new Test();
obj.Method2; Console.ReadLine();
}
}
}
Windows Programming
In development of any application we need a user interface (UI) to communicate with end users and User
Interfaces are of 2 types:
1. CUI (Character User Interface)
2. GUI (Graphical User Interface)

Initially we have only CUI, E.g.: Dos, Unix OS etc., where these applications suffers from few criticisms like:
1. They are not user friendly, because we need to learn the commands first to use them.
2. They do not allow navigating from one place to other.

To solve the above problems, in early 90's GUI applications are introduced by Microsoft with its Windows OS,
which has a beautiful feature known as “Look and Feel”. To develop GUI's Microsoft has provided a language also in
90's only i.e. VB (Visual Basic), later when .NET was introduced the support for GUI has been given in all languages
of .NET.

116
Developing Graphical User Interfaces:
To develop GUI’s we need some special components known as controls and those controls are readily
available in .NET Language's as classes under the namespace System.Windows.Forms. All the control classes that are
present under this namespace were grouped into different categories like:
• Common Controls
• Container Controls
• Menus and Tool Bar Controls
• Data Controls
• Components
• Printing Controls
• Dialog Controls
• Reporting Controls

Properties, Methods and Events:


Whatever the control it was, every control has 3 things in common like: properties, methods and events.
1. Properties: these are attributes of a control which have their impact on look of the control.
E.g.: Width, Height, BackColor, ForeColor, etc.
2. Methods: these are actions performed by a control.
E.g.: Clear(), Focus(), Close(), etc.
3. Events: these are time periods which specify when an action has to be performed.
E.g.: Click, Load, KeyPress, MouseOver, etc.

Note: the parent class for all the control classes is the class “Control”, which is defined with the properties, methods
and events that are common for each control like Button, TextBox, Form, Panel, etc.
How to develop a GUI Application?
To develop a GUI Application the base control that has to be created first is Form. To create the Form, first
define a class inheriting from the pre-defined class “Form” so that the new class also becomes a Form.
E.g.: public class Form1 : Form
To run the Form class we have defined call the static method “Run” of “Application” class by passing the
instance of Form we have created as a parameter.
E.g: Form1 f = new Form1(); Application.Run(f); or Application.Run(new Form1());
Note: we can develop a windows application either by using a notepad following the above process as well as under
Visual Studio also using “Windows Forms App” project template.
Developing Windows Application using Notepad: Open notepad, write the following code in it, save, compile and
then execute.

using System; using System.Windows.Forms;


public class Form1 : Form {
static void Main() {
Form1 f = new Form1();
Application.Run(f);
}
}
Developing Windows Applications using Visual Studio:

117
To develop a windows application under VS open the new project window, select “Windows Forms App”
project template and specify a name to the project, e.g.: WindowsProject.
By default the project comes with 2 classes in it:
• Form1
• Program

Form1 is the class which is defined inheriting from predefined class Form.
E.g.: public partial class Form1 : Form

Here the class Form1 is partial which means it is defined on multiple files, those are:
• Form1.cs
• Form1.Designer.cs

Note: we will not find the Form1.Designer.cs file open by default to open it go to solution explorer expand the node
Form1.cs and under it we find Form1.Designer.cs file, double click on it to open.

Windows applications developed under VS have 2 places to work with:


• Design View
• Code View

Design View is the place where we design the application; this is accessible both to programmers and end
user's whereas Code View is the place where we write code for the execution of application, this is accessible only
to programmers.

Note: because of the design view what VS provides we call it as WYSIWYG IDE (What You See Is What You Get).
Program is a static class and in this class we find a Main method under which object of class Form1 is created
for execution, as following:
Application.Run(new Form1());
Note: Program class is the main entry point of the project from where the execution starts.
Adding new Forms in the project:
A project can contain any no. of forms in it, to add a new form under our project i.e. “WindowsProject”,
open Solution Explorer => right click on project and select Add => "Windows Form", which adds a new form Form2.cs.
To run the new form, go to Program class and change the code under Application.Run method as Form2.
E.g.: Application.Run(new Form2());
Properties: as we are aware that every control has properties, methods and events, to access the properties of a
control VS provides “Property Window” that lists all the properties of a control, to open Property Window select the
control and press F4. We can change any property value in the list of properties, under property window like Width,

118
Height, BackColor, Font, ForeColor etc., for which we can see the impact immediately after changing the property
value. To test this go to properties of Form2 we have added right now and change any property value you want.

Whenever we set a value to any property of a control under property window, VS on behalf of us writes all
the necessary code by assigning values to the properties we have modified. We can view that code under
InitializeComponent() method of the class which is called in constructor of the class. To view code under
InitializeComponent method, go to Code View and right click on the method called in constructor and select “Go to
definition”, this takes us to Form2.Designer.cs file and here also we find the same class Form2 because it is partial.
Setting properties to control manually by writing the code in Notepad:
using System; using System.Drawing; using System.Windows.Forms;
public class Form2 : Form {
public Form2() {
InitializeComponent();
}
private void InitializeComponent() {
this.Text = "Form2"; this.BackColor = Color.Pink; this.Size = new Size(400, 400);
}
static void Main() {
Application.Run(new Form2());
}
}
Event: it is a time period which tells when an action has to be performed i.e. when exactly we want to execute a
method. Every control will have no. of events under it where each event occurs on a particular time period. We can
access the events of a control also under property window only. To view them in the property window choose events
Tab on top of the property window. If we want to write any code that should execute when an event occurs double
click on the desired event corresponding to a control, which takes you to code view and provides a method for
writing the code.
Now in our project add a new form Form3.cs, go to its Events, double click on Load Event and write the
following code under Form3_Load method that is generated in Code View:
MessageBox.Show("Welcome to windows applications.");
Again go to design view, double click on the Click Event and write following code under Form3_Click method:
MessageBox.Show("You have clicked on the form.");
What happens when we double click on an event of a control in the property window?
When we double click on an event in property window internally a method gets generated for writing the
code and that method has a special name "Event Procedure", which is a block of code that is bound with an event
of control and gets executed whenever the event occurs. The code written under event procedure will be executed
by the event whenever the event occurs by taking the help of a delegate internally, as following:

119
In the above case whenever the Event occur it will call the delegate which then executes the event
procedure that is bound with the event; because a delegate is responsible for execution of the event procedure first
the control, event, delegate and event procedure should be bound with each other as following:

Syntax: <control>.<event> += new <delegate> (<event procedure>)


E.g.: this.Load += new EventHandler(Form3_Load);
button1.Click += new EventHandler(button1_Click);
textBox1.KeyPress += new KeyPressEventHandler(textBox1_KeyPress);

Events and Delegates are pre-defined under FCL (Events are defined in control classes and delegates are
defined under namespaces), what is defined here is only an event procedure. After defining the event procedure in
form class VS links the Control, Event, Delegate and Event Procedure with each other as we have seen above and
this can be found under the method InitializeComponent of “Designer.cs” file.

Note: 1 delegate can be used by multiple events to execute event procedures, but all events will not use the same
delegates, where different events may use different delegates to execute event procedures.
How to define an Event Procedure manually?
To define Event Procedures manually we need to follow a standard format as following:
Syntax: [<modifiers>] void <Name>(Object sender, EventArgs e) {
<Stmts>;
}
• Event Procedures are non-value returning methods.
• An event procedure can have any name but Visual Studio adopts a convention while naming them i.e.:
<control name>_<event>. E.g.: Form1_Load, button1_Click, textBox1_KeyPress.
• Every event procedure should take 2 mandatory parameters:
i. Object sender
ii. EventArgs e
Note: When we define event procedures manually we can give any name to them as per our choice.
Defining Event Procedures in Notepad:
using System; using System.Drawing; using System.Windows.Forms;
public class Form3 : Form {
public Form3() {
InitializeComponent();
}
private void InitializeComponent() {
this.Text = "Form3"; this.BackColor = Color.Pink; this.Size = new Size(400, 400);
this.Load += new EventHandler(TestProc1); this.Click += new EventHandler(TestProc2);
}
private void TestProc1(object sender,EventArgs e) {
MessageBox.Show("Load Event Occured.");
}
private void TestProc2(object sender,EventArgs e) {
MessageBox.Show("Click Event Occured.");
}
static void Main() {

120
Application.Run(new Form3());
}
}
Placing controls on a form:
By default we are provided with no. of controls where each control is a class. These controls are available
in ToolBox window on LHS of the studio, which displays all controls, organized under different Tabs (groups). To
place a control on the form either double click, on desired control or select the control and place it in the desired
location on form.
Note: use Layout toolbar to align controls properly.
How does a form gets created ?
When a form is added to the project internally following things takes place:
i. Defines a class inheriting from the pre-defined class “Form” so that the new class is also a Form.
E.g.: public partial class Form1 : Form
ii. Sets some initialization properties like Name, Text etc., under InitializeComponent method.
E.g.: this.Name = "Form1"; this.Text = "Form1";

How does a control gets placed on the form ?


When a control is placed on the form following things takes place internally:
1) Creates object of appropriate control class.
E.g.: Button button1 = new Button();
2) Sets some initialization properties that are required like Name, Text, Size, Location etc.,
E.g.: button1.Name = "button1"; button1.Text = "button1";
button1.Location = new Point(x, y); button1.Size = new Size(width, height);
3) Now the control gets added to form by calling Controls.Add method on current Form.
E.g.: this.Controls.Add(button1);
Note: All the above code will be generated by VS under InitializeComponent method with in the file Designer.cs.

The code that is present under a windows application is divided into 2 categories:
• Designer Code
• Business Logic

Code which is responsible for construction of the Form is known as designer code and code which is responsible for
execution of the Form is known as business logic. Designer code is generated by VS under InitializeComponent
method of “Designer.cs” file and business logic is written by programmers in the form of Event Procedures.
Before .NET 2.0 designer code and business logic were defined in a class present under a single file as following:
Form1.cs
public class Form1 : Form {
-Designer Code
-Business Logic
}
From .NET 2.0 with introduction of partial classes’ designer code and business logic were separated into 2 different
files but of the same class only as following:
Form1.cs
public partial class Form1 : Form {
-Business Logic

121
}
Form1.Designer.cs
partial class Form1 {
-Designer Code
}
Creating a Form and placing a Button on it using notepad:
using System; using System.Drawing; using System.Windows.Forms;
public class Form4 : Form {
Button button1;
public Form4() {
InitializeComponent();
}
private void InitializeComponent() {
button1 = new Button(); button1.Text = "Click Me"; button1.BackColor = Color.Magenta;
button1.Size = new Size(100, 50); button1.Location = new Point(100, 100);
button1.Click += new EventHandler(TestProc); this.Controls.Add(button1);
this.Text = "Form4"; this.BackColor = Color.Pink; this.Size = new Size(400, 400);
}
private void TestProc(object sender, EventArgs e) {
MessageBox.Show("Button is clicked.");
}
static void Main() {
Application.Run(new Form4());
}
}
Default Events: as we are aware every control has no. of events to it, but 1 event will be default for a Control. To
write code under that default event of Control directly double click on the control which takes to an event procedure
associated with that default event.
Control Default Event
Form Load
Button Click
TextBox TextChanged
CheckBox and RadioButton CheckedChanged
ListView, ListBox, ComboBox and CheckedListBox SelectedIndexChanged
Working with Events and Event Procedures:
The concept of events and event procedures has been derived from classical VB Language, but there an
event procedure can be bound with only single event of a single control, where as in .NET it can be bound with
multiple events of a single control as well as with multiple controls also.
Binding an Event Procedure with multiple Events of a Control:
Add a new form to the project Form4 and double click on it which defines an event procedure Form4_Load,
now bind the same event procedure with click event of form also, to do this go to events of form, select click event
and click on the drop down beside, which displays the list of event procedures available, select “Form4_Load” event
procedure that is defined previously which binds the event procedure with click event also, now under the event
procedure write the following code and execute:
MessageBox.Show("Event Procedure bound with multiple Events of a Control.");

122
Binding an Event Procedure with multiple Controls:
Add a new form in the project i.e. Form5 and design it as below. Now double click on button1 which generates
a click event procedure for button1, bind that event procedure with button2, textBox1, textBox2 and Form5 also
and write the following code under the event procedure: MessageBox.Show("Control is clicked by the user..");

Binding an Event Procedure with multiple Controls & identifying the “Type” of Control which is raising the Event:
Add a new form in the project i.e. Form6 and design it same as Form5. Now double click on button1 which
generates a click event procedure for button1, bind that event procedure with button2, textBox1, textBox2 and
Form6 also and write the following code under the event procedure:
if (sender.GetType().Name == "Button") or if (sender is Button)
MessageBox.Show("Button is clicked by the user.");
else if (sender.GetType().Name == "TextBox") or if (sender is TextBox)
MessageBox.Show("TextBox is clicked by the user.");
else
MessageBox.Show("Form6 is clicked by the user.");

When an event procedure is bound with multiple controls, any of the control can raise the event in runtime
and execute the event procedure, but the instance of control which is raising the event will be coming into the event
procedure and captured under the parameter "sender" of event procedure as following:

As sender is of type object it's capable of storing instance of any class in it, so after the instance of the
control class is captured under sender by calling GetType() method on it we can identify the type of control to which
that instance belongs as we have performed above.
Binding an Event Procedure with multiple Controls and identifying the “Exact Control” which is raising the Event:
Add a new form in the project i.e. Form7 and design it same as Form5. Now double click on button1 which
generates a click event procedure for button1, bind that event procedure with button2, textBox1, textBox2 and
Form7 also and write the following code under the event procedure:

if (sender is Button) {
Button b = sender as Button;
if (b.Name == "button1")

123
MessageBox.Show("Button1 is clicked");
else
MessageBox.Show("Button2 is clicked");
}
else if (sender is TextBox) {
TextBox tb = (TextBox)sender;
if (tb.Name == "textBox1")
MessageBox.Show("TextBox1 is clicked");
else
MessageBox.Show("TextBox2 is clicked");
}
else
MessageBox.Show("Form7 is clicked");

When an event procedure is bound with multiple controls and if we want to identify the exact control which
is raising the event, we need to identify the “Name (Instance Name)” of control. But even if “sender” represents the
control which is raising the event, using sender we cannot find the control name because we are already aware that
instance of a class can be stored in its parent's variable and make it as a reference but with that reference we cannot
access the child class’s members (Rule No. 3 of Inheritance). So if we want to find the name of control that is raising
the event we need to convert sender back into appropriate control type (Button or TextBox) from which it is created
by performing an explicit conversion and then find out the name of control instance. We can convert sender into
control type in any of the following ways:

Button b = sender as Button; or Button b = (Button)sender;


TextBox tb = sender as TextBox; or TextBox tb = (TextBox)sender;
Working with Controls
RadioButton and CheckBox Controls:
We use these controls when we want the users to select from a list of values provided. RadioButton control
is used when we want to allow only a single value to select from the set of values whereas CheckBox control is used
when we want to allow multiple selections.

Note: as RadioButton control allows only single selection when we want to use them under multiple options or
questions we need to group related RadioButton's, so that 1 can be selected from each group, to group them we
need to place RadioButtons on separate container controls like Panel, GroupBox, TabControl etc.
Both these 2 controls provides a common boolean property Checked which returns true if the control is
selected or else returns false, using which we can identify which option has been chosen by the users. Now add a
new form in the project and write the below code by designing the form as following:

Code under “Show Selected Radio Button” button’s click event:


if (radioButton1.Checked)

124
MessageBox.Show("Radio Button1 is selected");
else if (radioButton2.Checked)
MessageBox.Show("Radio Button2 is selected");
else if (radioButton3.Checked)
MessageBox.Show("Radio Button3 is selected");

Code under “Show Selected Check Box’s” button’s click event:


if (checkBox1.Checked)
MessageBox.Show("Check Box1 is selected");
if (checkBox2.Checked)
MessageBox.Show("Check Box2 is selected");
if (checkBox3.Checked)
MessageBox.Show("Check Box3 is selected");
Checked Changed Event: this is the default event of both the above 2 controls which occurs when the controls are
selected as well as de-selected also. To work with the event design a form as following:

GroupBox

GroupBox

• Change the name of every control on the form for example ‘Name’ TextBox as ‘txtName’, ‘Total Fees’
TextBox as ‘txtFees’, ‘Reset Form’ Button as ‘btnReset’ and ‘Close Form’ button as ‘btnClose’, ‘Courses’
GroupBox as ‘gbCourses’, ‘Track’ GroupBox as ‘gbTrack’, ‘C (750)’ CheckBox as ‘cbC’, ‘Normal’ RadioButton
as ‘rbNormal’ and so on.
• Change the ReadOnly property of ‘Total Fees’ TextBox as true so that it becomes non editable, enter ‘0’ as
a value in Text property and also set the TextAlign property as right.
• Set the Tag property for each CheckBox and RadioButton with their corresponding fees values and it should
be ‘0’ for Normal RadioButton. Tag property is used for associating user defined data to any control just like
Text property, but Text value is visible to end user and Tag value is not visible to end user.
• Double click on any one CheckBox so that CheckedChanged Event procedure gets generated; bind that
event procedure with all the remaining CheckBox’s.
• Double click on any one RadioButton so that CheckedChanged Event procedure gets generated; bind that
event procedure with all the remaining RadioButton’s.
• Now go to Code View and write the following code.

Class/Global Declarations: int Count = 0;


Code under CheckedChanged Event Procedure of all CheckBox’s:
radioButton1.Checked = true;
int Amt = int.Parse(txtFees.Text);
CheckBox cb = sender as CheckBox;

125
if (cb.Checked) {
Count += 1; Amt += Convert.ToInt32(cb.Tag);
}
else {
Count -= 1; Amt -= Convert.ToInt32(cb.Tag);
}
txtFees.Text = Amt.ToString();
Code under CheckedChanged Event Procedure of all RadioButton’s:
int Amt = int.Parse(txtFees.Text);
RadioButton rb = sender as RadioButton;
if (rb.Checked)
Amt += Convert.ToInt32(rb.Tag) * Count;
else
Amt -= Convert.ToInt32(rb.Tag) * Count;
txtFees.Text = Amt.ToString();
Code under Click Event Procedure of Reset Form Button:
foreach (Control ctrl in gbCourses.Controls) {
CheckBox cb = ctrl as CheckBox; cb.Checked = false;
}
foreach (Control ctrl in this.Controls) {
if (ctrl is TextBox) {
TextBox tb = ctrl as TextBox; tb.Clear();
}
}
txtFees.Text = "0"; txtName.Focus();
Code under Click Event Procedure of Close Form Button: this.Close();
Button, Label and TextBox Controls:

1. Button: used for taking acceptance from a user to perform an action.


2. Label: used for displaying static text on the UI.
3. TextBox: used for taking text input from the user and this control can be used in 3 different ways:
I. Single-Line Text (d)
II. Multi-Line Text (Text Area)
III. Password Field
The default behavior of the control is single line text; to make it multiline set the property Multiline of the
control as true. By default the text area will not have any scroll bars to navigate up and down or left and right, to get
them set the ScrollBars property either as Vertial or Horizontal or Both, default is none.

Note: by default the WordWrap property of the control is set as true disabling horizontal scroll bar so set it as false
to get horizontal scroll bar.

To use the control as a password field either set the PasswordChar property of control with a character we
want to use as Password Character like * or # or $ or @ etc., or else set the UseSystemPasswordChar property as
true which indicates the text in the control should appear as the default password character.

126
MaskedTextBox:
This control looks same as a TextBox but can be used for taking the input in specific formats from the users.
To set a format for input, select the Mask property in property window and click on the button beside it, which opens
a window, in it we can either choose a mask from list of available masks or select custom and specify our own mask
format using zeros in the mask textbox below as following:
Railway PNR: 000-0000000 Credit Card No: 0000-0000-0000-0000 Aadhar No: 0000 0000 0000

Even if we set the Mask as date it will not validate for a valid date and if we want to do that we need to
explicitly write code for the controls TypeValidationCompleted event.
To work with all the above controls add a new form in the project and design it as following:

Setting Tab Order of Form Controls:


While working with a windows application we navigate between controls using the Tab key of key board.
By default Tab key navigates the focus between controls in the same order how they are placed on form. If we want
to set the sequence of tab on our own, it can be done by setting the “Tab Order”. To do this go to View Menu and
click on “Tab Order” Menu Item which shows the current tab order, now click on each control in a sequence how we
want to move the tab, again go to view menu and click on “Tab Order.” Menu Item.

In the above form check the following business rules (Validations):


1. Check the user name, password and confirm password fields to be mandatory.
2. Check password characters to be ranging between 8 and 16 characters.
3. Check confirm password to be matching with password.
4. Disable the password TextBox’s once the above 2 rules are satisfied.
5. Check DOB to accept a valid date in “dd/MM/yyyy” format and also check user has attained 18 years of age
at the time of registration and its mandatory field.
6. Check Mobile TextBox accepts numerics and back spaces only and also Mobile No. should start with digits
6 or 7 or 8 or 9 and should be minimum 10 digits and maximum 10 digits, but not mandatory field.
7. Check Email TextBox accepts valid Email Id’s only, but not mandatory field.
8. Allow users to close the form if required at any time with out any restrictions.

To perform the first 4 validations first set the MaxLength property of both password textbox's to 16 so that
they will accept only 16 chars, then define a Validating event procedure for user name textbox and bind that event
procedure with both the password textbox's also. Now write the following code under the event procedure:

TextBox tb = sender as TextBox;


if (tb.Text.Trim().Length == 0) {

127
MessageBox.Show("Cannot leave the field empty.", "Mandatory Field Error", MessageBoxButtons.OK,
MessageBoxIcon.Error); e.Cancel = true; return;
}
if (tb.Name != "txtName") {
if (tb.Text.Trim().Length < 8) {
MessageBox.Show("Password should be between 8 to 16 chars", "Password Error", MessageBoxButtons.OK,
MessageBoxIcon.Error); e.Cancel = true; return;
}
}
if(tb.Name == "txtCPwd") {
if(txtPwd.Text != txtCPwd.Text) {
DialogResult dr = MessageBox.Show("Confirm password is not matching with password. \n\nDo you remember
the password?", "Confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if(dr == DialogResult.Yes) { txtCPwd.Clear(); txtCPwd.Focus(); }
else { txtPwd.Clear(); txtCPwd.Clear(); txtPwd.Focus(); }
return;
}
txtPwd.Enabled = txtCPwd.Enabled = false;
}
• Validating event occurs when the focus is leaving the control and validates the content entered in the
control.
• Some events are associated with properties with them e.g.: Validating, KeyPress etc., if we want to consume
the properties of an event under its event procedure we can make use of the parameter "e" of the event
procedure which refers to properties of current executing event.
• In the above code “Cancel” is a property of validating event, which when set as true restricts the focus not
to leave the control.

To perform date validation, generate Load event procedure for Form control and set ValidatingType property
for MaskedTextBox to DateTime so that it accepts only Date value as following:
mtbDOB.ValidatingType = typeof(DateTime);
Now generate TypeValidationCompleted event handler for Date MaskedTextBox and write the following
code in it by importing System.Globalization namespace:

if (mtbDOB.Text.Replace("/", "").Trim().Length > 0) {


DateTime dt;
if (DateTime.TryParseExact(mtbDOB.Text, "dd/MM/yyyy", null, DateTimeStyles.None, out dt) == false) {
MessageBox.Show("Date entered must be in a valid date format of dd/MM/yyyy.", "Date Error",
MessageBoxButtons.OK, MessageBoxIcon.Error); e.Cancel = true;
}
else {
if (dt > DateTime.Now.AddYears(-18)) {
MessageBox.Show("Minimum 18 years of age is required for registration.", "Date Error",
MessageBoxButtons.OK, MessageBoxIcon.Error); e.Cancel = true;
}
}
}

128
else {
MessageBox.Show("Date of birth field is mandatory.", "Warning", MessageBoxButtons.OK,
MessageBoxIcon.Warning); e.Cancel = true;
}
If we want the Phone No TextBox to accept only numeric values and back spaces first set the MaxLength
property as 10, then define a KeyPress event procedure for Phone No TextBox and write following code in it:

if (char.IsDigit(e.KeyChar) == false && Convert.ToInt32(e.KeyChar) != 8) {


MessageBox.Show("Enter numeric values only"); e.Handled = true;
}
• KeyPress event occurs when we press and release a key while the focus is in the control.
• KeyChar property of KeyPress gets the key value corresponding to the key pressed.
• Handled property when set as true will restrict the key value to enter into the control.
• Char.IsDigit(char) will return true if the given char is a numeric or else returns false.
• Convert.ToInt32(char) will return ascii value of the given character.

If we want Mobile No TextBox to start with digits 6, 7, 8 and 9 and should have minimum of 10 digits, generate
a Validating event procedure for Mobile No. TextBox and write the following code in it by importing
System.Text.RegularExpressions namespace:

if (txtMobile.Text.Length > 0) {
Regex mobilePattern = new Regex(@"^[6-9]\d{9}$");
if (!mobilePattern.IsMatch(txtMobile.Text)) {
MessageBox.Show("Entered number is not a valid mobile number.", "Phone Error", MessageBoxButtons.OK,
MessageBoxIcon.Error); e.Cancel = true;
}
}
If we want Email TextBox to accept a valid Email Id generate a Validating event procedure to Email Id
TextBox and write the following code in it:

if (txtEmail.Text.Length > 0) {
Regex emailPattern = new Regex(@"^\w+[\w-\.]*\@\w+((-\w+)|(\w*))\.[a-z]{2,3}$");
if (!emailPattern.IsMatch(txtEmail.Text)) {
MessageBox.Show("Entered string is not in a valid email format.", "Email Error", MessageBoxButtons.OK,
MessageBoxIcon.Error); e.Cancel = true;
}
}
To close the form even from mandatory fields go to properties of Close Button and set its 'CausesValidation'
property as false so that code under that button gets executed before the execution of any other controls validating
event. Now write the following code under Close Button Click Event:

DialogResult dr = MessageBox.Show("Are you sure of closing the form?", "Confirmation",


MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (dr == DialogResult.Yes) {
foreach (Control ctrl in this.Controls) {
if (ctrl is TextBoxBase) { ctrl.CausesValidation = false; }

129
}
this.Close();
}
Note: When we set CausesValidation = false for TextBox it will restrict validating event of the control not to occur so
that focus leaves the textbox and form gets closed.
Code under Save Button Click Event Procedure:
MessageBox.Show("Data saved to database");
Code under Clear Button Click Event Procedure:
foreach(Control ctrl in this.Controls) {
if(ctrl isTextBoxBase) {
TextBoxBase tb = ctrl as TextBoxBase; tb.Clear();
}
}
txtPwd.Enabled = txtCPwd.Enabled = true; txtName.Focus();
MessageBox: This control is used for displaying messages with in a windows application by calling its static method
“Show”, which returns a value of type DialogResult (enum), using it we can find out which button has been clicked
on the MessageBox like Ok or Yes or No or Cancel etc. Show is an overloaded method that is defined with different
overloads as following:
• Show(string msg) => Dialog Result
• Show(string msg, string caption) => Dialog Result
• Show(string msg, string caption, MessageBoxButtons buttons) => Dialog Result
• Show(string msg, string caption, MessageBoxButtons buttons, MessageBoxIcon icon) => Dialog Result

MessageBoxButtons is an enum which provides a list of options to choose what buttons should be displayed
on the MessageBox for the user to select.

MessageBoxIcon is an enum which provides a list of options to choose what icon should be displayed on
the MessageBox describing about the message like Error or Warning or Question or Information etc., icons.
ComboBox, ListBox, CheckedListBox: These controls are also used for providing users with a list of values to choose
from. ComboBox allows only single selection but it is editable which gives a chance to either select from the list of
values available or enter a new value, it’s a combination of 2 controls DropDownList + TextBox. ListBox by default
allows single selection only but can be changed to multi-selection by setting the SelectionMode property either to
MultiSimple [Mouse Click] or MultiExtended [Ctrl + Mouse Click]. CheckedListBox is same as ListBox but displays a
CheckBox beside every item for selection and by default it allows multi-selection.
Adding values to the controls: we can add values to the 3 controls in different ways like:
1. In the properties of the control we find a property Items, select it and click on the button beside it which
opens a window, enter the values we want to add, but each in a new line.
2. By using Items.Add method of the control we can add values, but only one at a time.
<List Control>.Items.Add(object value)
3. By using Items.AddRange method of the control an array of values can be added at a time.
<List Control>.Items.AddRange(object[] values)
4. By using DataSource property of the control a DataTable can be bound to it so that all the records of table
gets bound to the control, but as it can display only a single column we need to specify the column to be
displayed using the DisplayMember property.
<List Control>.DataSource = <DataTable>; <List Control>.DisplayMember = <ColumnName>;

130
Accessing all values from the controls: for accessing all the values from List Controls they provide a property known
as Items which returns an object[] of all items.
<List Control>.Items => Object[]

Accessing selected values from the controls: for accessing the selected values from List Controls we need to make
use of the following properties:
ComboBox: Text => string SelectedItem => object SelectedIndex => int
ListBox: SelectedItem => object SelectedIndex => int SelectedItems => object[] SelectedIndices => int[]
CheckedListBox: CheckedItems => object[] CheckedIndices => int[]
Add a new form in the project and design it as below, then go to Items property of the ComboBox control,
click on the button beside it and enter a list of countries in the window opened.

Code under Form Load Event Procedure:


listBox1.Items.Add("AP"); listBox1.Items.Add("Tamilnadu"); listBox1.Items.Add("Orissa");
listBox1.Items.Add("Karnataka"); listBox1.Items.Add("Kerala"); listBox1.Items.Add("Maharastra");
string[] cities = { "Bengaluru", "Chennai", "Delhi", "Hyderabad", "Kolkota", "Mumbai" };
checkedListBox1.Items.AddRange(cities);
Code under ComboBox KeyPress Event Procedure:
if(Convert.ToInt32(e.KeyChar) == 13) { Adding a new value entered into the
if(comboBox1.FindStringExact(comboBox1.Text) == -1) { ComboBox when we hit the enter key and
comboBox1.Items.Add(comboBox1.Text); the given value is not existing under the list
} of values.
}
Code under “Show Selected Country” Button Click Event Procedure:
MessageBox.Show(comboBox1.Text); MessageBox.Show(comboBox1.SelectedItem.ToString());
Code under “Show Selected States” Button Click Event Procedure:
foreach (object obj in listBox1.SelectedItems) { MessageBox.Show(obj.ToString()); }
Code under “Show Selected Cities” Button Click Event Procedure:
string str = null;
foreach (object obj in checkedListBox1.CheckedItems) { str += obj.ToString() + ", "; }
str = str.Substring(0, str.Length - 2); int pos = str.LastIndexOf(",");
if (pos != -1) {
str = str.Remove(pos, 1); str = str.Insert(pos, " and");
}
MessageBox.Show(str);
SelectedIndexChanged: it is the default event of all the above 3 controls which gets raised once a value is selected
in the list, to test this add a new form in the project, design it as below and add the values “Quarter1, Quarter2,
Quarter3 and Quarter4” under the first ComboBox by using its items property and write the code.

131
Code under first ComboBox SelectedIndexChanged Event Procedure:
comboBox2.Text = “”; comboBox2.Items.Clear();
switch (comboBox1.SelectedIndex) {
case 0: comboBox2.Items.AddRange(new string[] { "January", "February", "March" } ); break;
case 1: comboBox2.Items.AddRange(new string[] { "April", "May", "June" } ); break;
case 2: comboBox2.Items.AddRange(new string[] { "July", "August", "September" } ); break;
case 3: comboBox2.Items.AddRange(new string[] { "October", "November", "December" } ); break;
}
PictureBox: We use this control for displaying images in our Application and to load an image in to the control we
can use any of the following properties:
ImageLocation = <path of the image>
Image = Image.FromFile(string ImgPath)
Image = Image.FromStream(Stream stream)
Use BorderStyle property to control what type of border we want for the PictureBox, with any of the
following values:
None [d] FixedSingle Fixed3D
Use SizeMode property of the control to set image placement and control sizing under the PictureBox which
can be set with any of the following values:
Normal [d] StretchImage AutoSize CenterImage
Dialog Controls:
These are special controls which provide an interface for displaying a list of values too choose from or for
entering of new values, we have 5 dialog controls like ColorDialog, FolderBrowserDialog, FontDialog, OpenFileDialog
and SaveFileDialog. Dialog controls are not shown directly on the form even after adding them, we can see them at
bottom of the studio in design time, to make them visible in runtime we need to explicitly call the method
ShowDialog() on the controls instance, which returns a value of type DialogResult (enum), using it we can find out
which button has been clicked on the DialogControl like Ok button or Cancel button.

Dialog Controls never performs any actions they are only responsible for returning the values to application
developers which has been chosen by end users or entered by the end users and then the developers are responsible
for capturing those values to perform the necessary actions. To capture the values that are chosen or entered by
end users we are provided with following properties:
ColorDialog: Color FolderBrowserDialog: SelectedPath
FontDialog: Font OpenFileDialog & SaveFileDialog: FileName

Design a new form as below, add the ColorDialog, FontDialog, OpenFileDialog and SaveFileDialog controls
to the form and write the below code:

132
Picture Box

Code under Change Color Button: colorDialog1.Color = button1.BackColor;


DialogResult dr = colorDialog1.ShowDialog();
if(dr == DialogResult.OK) { button1.BackColor = colorDialog1.Color; }
Code under Change Font Button: fontDialog1.Font = button2.Font;
DialogResult dr = fontDialog1.ShowDialog();
if(dr == DialogResult.OK) { button2.Font = fontDialog1.Font; }
Code under Load Image Button:
openFileDialog1.FileName = "";
openFileDialog1.Filter = "Image Files|*.jpg|Icon Images|*.ico|All Files|*.*";
DialogResult dr = openFileDialog1.ShowDialog();
if (dr != DialogResult.Cancel) {
string imgPath = openFileDialog1.FileName; pictureBox1.ImageLocation = imgPath;
}
Code under Save Image Button:
saveFileDialog1.FileName = "*.jpg";
saveFileDialog1.Filter = "Jpeg Images|*.jpg|Icon Images|*.ico|All Files|*.*";
DialogResult dr = saveFileDialog1.ShowDialog();
if (dr != DialogResult.Cancel) {
string imgPath = saveFileDialog1.FileName; pictureBox1.Image.Save(imgPath);
}
Dock Property: It’s a property present under all controls except form, which defines which border of the control is
bound to the container. The property can be set with any of the following values:
• None: in this case any of the controls border is not bound to its container.
• Left, Right, Top and Bottom: in this case what option we select from the 4, that border of the control is
bound with the same border of the container.
• Fill: in this case all the four borders of the control will be bound with its container, so it occupies all empty
space present on the container but leaving the space to existing controls.
Timer Control: It’s a control which can raise an event at user defined intervals i.e. we can specify an interval time
period and once the interval elapses automatically the event procedure associated with the control gets executed.

Members of Timer:
1. Tick: it is an event which occurs whenever the specified interval time elapses.
2. Interval: it is a property using which we specify the frequency of execution in milliseconds.
3. Start(): it is a method to start the execution of timer.
4. Stop(): it is a method to stop the execution of timer.
Developing an Image Viewer Application:
Add a new form in the project. Place a panel control on the form and set its dock property as right. Place a
picture box control on the form and set its dock property as fill and size mode property as “StretchImage”. Now
design the panel present on the right hand side of the form as following:

133
List Box
Panel

Name the buttons as btnLoad, btnPrev, btnNext, btnStart and btnStop. Set the Enabled property of btnPrev,
btnNext and btnStart button as false, set the Visible property of btnStop as false, then go to properties of form and
under its CancelButton property select the button as btnStop which gets mapped to Esc key of keyboard. Add the
FolderBrowserDialog and Timer controls to the form, set the Interval property of Timer as 2991 and write the
following code in Code View:

using System.IO;
Declarations: object[] OldVals;
Code under Load Images Button Click Event Procedure:
DialogResult dr = folderBrowserDialog1.ShowDialog();
if (dr == DialogResult.OK) {
string dirPath = folderBrowserDialog1.SelectedPath; string[] files = Directory.GetFiles(dirPath, "*.jpg");
if(files.Length > 0) { listBox1.Items.Clear(); listBox1.Tag = dirPath;
foreach (string file in files) {
int pos = file.LastIndexOf("\\"); string fname = file.Substring(pos + 1); listBox1.Items.Add(fname);
}
btnPrev.Enabled = false; btnNext.Enabled = true; btnStart.Enabled = true;
}
else { MessageBox.Show("Selected folder doesn't contain any Jpeg Images.", "Image Viewer",
MessageBoxButtons.OK, MessageBoxIcon.Information); }
}
Code under ListBox SelectIndexChanged Event Procedure:
pictureBox1.ImageLocation = listBox1.Tag + "\\" + listBox1.SelectedItem;
Code under Prev Button Click Event Procedure: listBox1.SelectedIndex -= 1;
Code under Next Button Click Event Procedure: listBox1.SelectedIndex += 1;
Code under Timer Tick Event Procedure:
if (listBox1.SelectedIndex < listBox1.Items.Count - 1) { listBox1.SelectedIndex += 1; }
else { btnStop.PerformClick(); } //PerformClick will invoke click event procedure of the button.
Code under Start Slide Show Button Click Event Procedure:
OldVals = new object[3]; OldVals[0] = FormBorderStyle; OldVals[1] = WindowState; OldVals[2] = panel1.Width;
this.WindowState = FormWindowState.Maximized; this.FormBorderStyle = FormBorderStyle.None;
panel1.Width = 0; btnStop.Visible = true; timer1.Start();
Code under Stop Slide Show Button Click Event Procedure:
timer1.Stop(); btnStop.Visible = false; panel1.Width = (int)OldVals[2];
this.WindowState = (FormWindowState)OldVals[1]; this.FormBorderStyle = (FormBorderStyle)OldVals[0];
AcceptButton and CancelButton Properties of the Form Control:
Under Form we have 2 properties AcceptButton and CancelButton which allows us to map buttons on a
form with keyboard keys. AcceptButton property if bound with a button that button gets clicked whenever we press
Enter key of key board. CancelButton property if bound with a button that button gets clicked whenever we press

134
Esc key of key board. To set them go to properties of form select either AcceptButton or CancelButton properties
which will display the list of buttons on form select a button from them.
Adding Menu's to a Form:
To add menu's to Form first we need to place a MenuStrip control on the Form which is present under
Menu's and Toolbar’s Tab of Toolbox, which sits on top of the Form as the dock property is set as Top.

To add a Menu on MenuStrip click on LHS corner of it which shows a textbox asking to “Type Here”, enter
Text in it which adds a Menu, and repeat the same process for adding of multiple Menu's.

To add a MenuItem under a menu, click on the Menu which shows a textbox below asking to “Type Here”,
enter Text in it which adds a MenuItem, and repeat the same process for adding of multiple MenuItems.
Note: both Menu and MenuItem are objects of the class ToolStripMenuItem.

If we want Menu's to be responding for "Alt Keys" of keyboard prefix with "&" before the character that
should respond for Alt.
E.g.: &File &Edit F&ormat

To define a shortcut for MenuItems so that they respond to keyboard actions, go to properties of
MenuItem, select “Shortcut Keys” Property, click on drop down beside it, which displays a window, in that window
choose a modifier Ctrl or Alt or Shift and then choose a Key from ComboBox below.

To group related MenuItems under a Menu we can add Separators between MenuItems, to do it right click
on a MenuItem and select Insert => separator which adds a separator on top of the MenuItem.
Note: same as we inserted a separator we can also insert a MenuItem if required, in the middle.
If we want to display any Image beside MenuItem right click on it and select “Set Image” which opens a
window, select Local Resource and click on Import button which opens a DialogBox, using it select an image from
your Hard disk.

Sometimes we find check mark beside MenuItem to identify a property is on or off, e.g.: Word Wrap under
Notepad. To provide check marks beside a MenuItem right click on it and select "Checked", but to check or uncheck
the item in run time we need to write code explicitly under click event of MenuItem as following:
if (<control>.Checked == true) { <control>.Checked = false; }
else { <control>.Checked = true; }
Multi Document Interface:
When designing an application it can contain any no. of forms in it, right now to run the desired form we
are explicitly specifying the form class name under Program class. But, when we provide the application to client we
only give him the assemblies of the project (i.e. IL Code) so client doesn't have a chance to edit the class Program
and specify the form class name he wants to run.

To overcome the above problem we are provided with an approach known Multi-Document Interface,
where in this approach an application will be having only one form as a startup Form which is referred as MDI Parent
or MDI Container, so that clients don't require changing the form name under program class at any time.
Rest of the forms in application will be under the control of MDI Parent Form and referred as MDI Children.
To make a form as MDI Parent set the property IsMdiContainer as true. To launch a form as child of parent create
object of child form class, set its MdiParent property with parent forms reference and then call Show() method.

135
Note: an application can have only one MDI Parent and all other forms must be children of parent which should
come and sit under parent. E.g.: Visual Studio by default launches as an MDI Container and the all other forms like
“New Project” and “Add New Item” windows will come and sit under it as its children.
Layout: When we have more than one child form opened at a time under parent, child forms will be arranged inside
the parent by using a layout for arrangement, which can be any of the following 4 options like:

I. Cascade (d): child forms are arranged 1 on the top of the other.
II. TileVertical: child forms are arranged 1 beside the other.
III. TileHorizontal: child forms are arranged 1 below the other.
IV. ArrangeIcons: all child forms icons are arranged with in the bottom of parent.

To test this add a new Form in the Project naming it as MdiParent.cs, set it’s IsMdiContainer property as
true to make it as a MDI Parent and also set the WindowState property as Maximized so that form gets launched to
the full size of the screen. Add a MenuStrip control to the Form and place 2 menus on it: Forms and Layout. Under
Forms Menu add a MenuItem for each child form to launch e.g.: Form1, Form2, Form3 etc. Under Layout Menu add
the following MenuItems: Arrange Icons, Cascade, Horizontal and Vertical and write the following code:

Code under Each Form's MenuItems: Form1 f = new Form1(); f.MdiParent = this; f.Show();
Code under Arrange Icons MenuItem: this.LayoutMdi(MdiLayout.ArrangeIcons);
Code under Cascade MenuItem: this.LayoutMdi(MdiLayout.Cascade);
Code under Vertical MenuItem: this.LayoutMdi(MdiLayout.TileVertical);
Code under Horizontal MenuItem: this.LayoutMdi(MdiLayout.TileHorizontal);
RichTextBox: This control works same as a TextBox but provides advanced text entry and editing features such as
character and paragraph formatting.

Members of RichTextBox Control:


• Properties: BackColor, ForeColor, WordWrap, Modified, Font, ScrollBars, SelectedText, SelectionColor etc.
• Methods: Cut(), Copy(), Paste(), Undo(), Redo(), Clear(), ClearUndo(), SelectAll(), DeselectAll(), Focus(),
ResetText(), Refresh(), LoadFile(string path, RichTextBoxStreamType fileType), SaveFile(string path,
RichTextBoxStreamType fileType)
RichTextBoxStreamType is an enum that specifies the types of input and output streams used to load and save
data in the control. The enum provides a list of constants like PlainText, RichText, UnicodePlainText etc.
User Controls
These are re-usable software components that are developed by application developers to consume under
their applications. We can develop User Controls in 2 ways:
• Creating a new control from existing controls.
• Inherited or extended controls.
In the first case we design a new control making use of existing controls and then write the required
behavior for the control. To design a control first we need to define a class (because every control is a class) inheriting
from the predefined class UserControl which provides a container for designing.
In the second case we don't design anything newly; we only copy the design of an existing control for adding
new functionalities or behavior that is required. In this case we define a class that is inheriting from the control class
for which new behavior has to be added.

136
To create a control in first process we need to add UserControl Item Template in the project which provides
a class that is inheriting from UserControl class, whereas in the second case we need to add Class Item Template and
then inherit from the control class we want to extend.

Note: to develop UserControls we are provided with Windows Forms Control Library project template. But the
controls whatever we develop are finally consumed from Windows Forms App. only.
People working on controls are classified as:
I. Component Developers
II. Application Developers
The person who develops controls is known as component developers and those who consume the controls for
developing applications are known as application developers. While developing controls the developer should first
design the control, write all the behavior to control and then define any required properties, methods and events
for the control.

Properties: these are defined to expose values that are associated with a control to application developer.
E.g.: Text property of TextBox, Checked property of CheckBox, ElapsedTime property of StopClock etc.

Methods: these are defined to perform actions so that application developers can call them when required.
E.g.: Clear(), Focus() methods of TextBox, Close() method of Form, Start(), Stop() method of StopClock etc.

Events: While developing a control the developer of control may not know what actions has to be performed at
some specific time periods. For example:
1. The developer of button control is not aware what should happen when end user clicks on the button.
2. What should happen when button is clicked by end user, will be decided by the application developer.
3. Even if decided by application developer it is the responsibility of component developer to execute the code
that is implemented by application developer whenever end user clicks on the button.
4. To perform the above, component developer first defines an event under his control and then asks the
application developer to write logic/code under an event procedure, binding it with the event he has
defined, so that whenever the event occurs or raises event procedure gets executed.
5. To execute the event procedure we are already aware that events will take the help of delegates.

Syntax to define event: [<modifiers>] event <delegate> <Name>

Note: As we are aware that events take help of delegates to execute event procedures, so while defining events we
must specify which delegate will be used by event to execute the event procedure. So first a delegate has to be
defined and then the event has to be defined. For example:
public delegate void EventHandler(object sender, EventArgs e);
public event EventHandler Click;
All delegates that are pre-defined in FCL which we are consuming right now under existing Controls =>
Events are declared with 2 parameters:
1. Object sender
2. EventArgs e
This is the reason why all our event procedures are also taking the same two parameters because we are
already aware that IO parameters of delegate should be same as the IO parameters of method it has to call.

137
Note: While defining events under user controls we can either make use of any pre-defined delegate or we can also
define our own delegates.

Using pre-defined delegate under a new event:


public event EventHandler MyClick;
In this case event procedure generated for MyClick event will take 2 parameters because EventHandler
delegate is defined with 2 parameters.

Using user-defined delegate under a new event:


public delegate void MyEventHandler();
public event MyEventHandler MyClick;
In this case event procedure generated for MyClick event will take 0 parameters because MyEventHandler
delegate is defined with no parameters. If delegate has any parameters then only event procedures will have
parameters or else event procedures will not have any parameters.

Tasks of Component Developer and Applications Developer related to Events:


Component Developer Tasks:
1. Define a delegate (optional).
2. Define an event under the control making use of a delegate (either pre-defined or user-defined).
3. Specify the time period when the event has to occur (Raising the event).
Application Developer Tasks:
1. Define an event procedure.
2. Bind the event, delegate and event procedure with each other.
Note: for an application developer the above 2 tasks gets performed implicitly when he double click on the event in
property window.
Creating a StopClock control: open a new project of type “Windows Forms Control Library” and name it as
“UserControlsProject”. By default the project comes with a class UserControl1 under the file UserControl1.cs, open
the solution explorer and rename the file as StopClock.cs so that the class name also changes to StopClock. Now
design the control as following:

Go to properties of MaskedTextBox, set the Mask property by clicking on the button beside the property,
select “Time (US)”, set the text property as “0000” and also set the ReadOnly property as True, then add a Timer
control and set the interval property as “997”. Now go to code view and write the following code in the class:

Code above the class (i.e. under the namespace directly):


public delegate void CloseEventHandler(); //Step 1: Defining a delegate to use under CloseClick Event.
Class Declarations:
[Category("Action")]
[Description("Occurs when close button is clicked on StopClock.")]
public event CloseEventHandler CloseClick; //Step 2: Defining a event making use of the above delegate.
int sec, min; string secstr, minstr;
Under Timer Tick Event:

138
if(sec < 59) { sec += 1; }
else {
sec = 0;
if(min < 59) { min += 1; }
else { min = 0; timer1.Stop(); }
}
if (sec < 10) { secstr = "0" + sec; }
else { secstr = sec.ToString(); }
if (min < 10) { minstr = "0" + min; }
else { minstr = min.ToString(); }
mtbTime.Text = minstr + secstr;
Under Start Button: timer1.Start();
Under Stop Button: timer1.Stop();
Under Reset Button: timer1.Stop(); mtbTime.Text = "0000"; min = sec = 0;
Under Close Button: if(CloseClick != null) { CloseClick(); } //Step 3: Raising CloseClick event that is defined above.
[Category(“Data”)]
[Description("Gets the elapsed time of current instance of StopClock.")]
public string ElapsedTime { //Defining a property to expose the elapsed time of StopClock.
get { return mtbTime.Text; }
}
public void Start() { //Defining a method to start the StopClock implicitly.
btnStart.Enabled = btnStop.Enabled = false; timer1.Start();
}
public void Stop() { //Defining a method to stop the StopClock implicitly.
timer1.Stop();
}
Consuming the control: Now open solution explorer, right click on the project, select build which compiles the
project and generates an assembly “UserControlsProject.dll” at following location:
<drive>:\<folder>\ControlsProject\ControlsProject\bin\Debug\netcoreapp3.1\UserControlsProject.dll

The control what we have developed can be consumed only by placing it on a Windows Form, so go to our
“WindowsProject” open the ToolBox, right click on it, select “Add Tab” which adds a new tab in the ToolBox enter a
name to it as “CSharp Controls”. Now right click on the “CSharp Controls” tab and select the option “Choose Items”
which opens a dialog box, click on the browse button in it and select the assembly “UserControlsProject.dll” from its
physical location which adds the control under the new tab.

Now add a new form in the project, place the StopClock control on it and run to test the control, once after
testing, to consume the property, methods and event we have defined in control do the following:

Consuming the property: place a new button on the Form, set its text as “Show Elapsed Time” and write the
following code under its click event:
MessageBox.Show(stopClock1.ElapsedTime);
Consuming the method: now to test the method we have defined write the following code under Form Load which
will start the StopClock implicitly when we run the form:
stopClock1.Start();

139
Consuming the event: now to test the CloseClick Event we have defined go to events of the StopClock control and
double click on the CloseClick event which defines an event procedure “stopClock1_CloseClick()”, write the following
code in it which gets executed when we click on the Close button of StopClock:
stopClock1.Stop(); MesageBox.Show(“Form is closing”); this.Close();
Developing an Inherited or Extended Control: In case of inherited controls we copy the design of an existing control
to a new control and then add/change its existing behavior in the new control.

Now let us create a “CustomTextBox” control inheriting from the existing TextBox control and add new
properties to it. To do this open our “UserControlsProject” under which we have developed the “StopClock”, add a
new “Code File” in the project naming it as “CustomTextBox.cs” and write the following code:

using System; using System.Windows.Forms; using System.ComponentModel;


namespace UserControlsProject {
public enum Options { Any, Char, CharOrDigit, Digit, Password }
public class CustomTextBox : TextBox {
[Category("Behavior")]
[Description("If set as true will accept decimal values when SetOption is digit.")]
public bool AcceptDecimal { get; set; } = false;

[Category("Behavior")]
[Description("Controls the type of values CustomTextBox has to accept.")]
public Options SetOption { get; set; } = 0;

public CustomTextBox() {
this.KeyPress += CustomTextBox_KeyPress;
}

private void CustomTextBox_KeyPress(Object sender, KeyPressEventArgs e) {


if (Convert.ToInt32(e.KeyChar) == 8) { return; }
switch (SetOption) {
case Options.Digit:
if (AcceptDecimal == true) {
if (Convert.ToInt32(e.KeyChar) == 46) {
return;
}
}
if (char.IsDigit(e.KeyChar) == false) {
MessageBox.Show("Enter numeric values only.", "Number Error", MessageBoxButtons.OK,
MessageBoxIcon.Error); e.Handled = true;
}
break;

case Options.Char:
if (char.IsLetter(e.KeyChar) == false && Convert.ToInt32(e.KeyChar) != 32) {
MessageBox.Show("Enter alphabet values only.", "Character Error", MessageBoxButtons.OK,

140
MessageBoxIcon.Error); e.Handled = true;
}
break;
case Options.CharOrDigit:
if (char.IsLetterOrDigit(e.KeyChar) == false) {
MessageBox.Show("Enter alpha-numeric values only.", "Alpha-Number Error", MessageBoxButtons.OK,
MessageBoxIcon.Error); e.Handled = true;
}
break;
case Options.Password:
if (char.IsLetterOrDigit(e.KeyChar) == false && Convert.ToInt32(e.KeyChar) != 35 &&
Convert.ToInt32(e.KeyChar) != 45 && Convert.ToInt32(e.KeyChar) != 64 &&
Convert.ToInt32(e.KeyChar) != 95) {
MessageBox.Show("Password can contain alphabets, numeric and special characters like -, _, # and @
only.", "Password Error", MessageBoxButtons.OK, MessageBoxIcon.Error); e.Handled = true;
}
break;
}
}
}
}
Recompile the project again so that the new control “CustomTextBox” gets added to
“UserControlsProject.dll”. To consume this control go back to our WindowsProject, right click on “CSharp Controls”
tab we added earlier, select “Choose Items”, click Browse, select the “UserControlsProject.dll” from its physical
location again, which adds the “CustomTextBox” control to our tab, i.e. under “StopClock” control. Now we can place
the control on any Form and consume it by setting the required “SetOption” value of the control. In case of “Digit”
option by setting “AcceptDecimal” property value as “true” that “TextBox” will accept “Decimal” points in it because
default value of “AcceptDecimal” is false.

Now add a new form in the project, add 6 CustomTextBox’s on the form and test them by setting the
SetOption values as following and for the last CustomTextBox also set AcceptDecimal as true:

ADO.Net

141
Pretty much every application deals with data in some manner, whether that data comes from memory,
databases, XML files, text files, or something else. The location where we store the data can be called as a Data
Source or Data Store where a Data Source can be a file, database, address books or indexing server etc.

Programming Languages cannot communicate with Data Sources directly because each Data Source adopts
a different Protocol (set of rules) for communication, so to overcome this problem long back Microsoft has
introduced intermediate technologies like Odbc and Oledb which works like bridge between the Applications and
Data Sources to communicate with each other.

ODBC (Open Database Connectivity) is a standard C programming language middleware API for accessing
database management systems (DBMS). ODBC accomplishes DBMS independence by using an ODBC driver as a
translation layer between the application and the DBMS. The application uses ODBC functions through an ODBC
driver manager with which it is linked, and the driver passes the query to the DBMS. An ODBC driver will be providing
a standard set of functions for the application to use, and implementing DBMS-specific functionality. An application
that can use ODBC is referred to as "ODBC-Compliant". Any ODBC-Compliant application can access any DBMS for
which a driver is installed. Drivers exist for all major DBMS’s as well as for many other data sources like Microsoft
Excel, and even for Text or CSV files. ODBC was originally developed by Microsoft in 1992.

1. It's a collection of drivers, where these drivers sit between the App's and Data Source's to communicate
with each other and more over we require a separate driver for each and every data source.
2. Odbc drivers comes along with your Windows O.S. and we can find them at the following location:
Control Panel => Administrative Tools => Odbc Data Sources
3. To consume these Odbc Drivers first we need to configure them with the data source by creating a "DSN"
(Data Source Name).
4. Odbc drivers are open source i.e. there is an availability of these Odbc Drivers for all the leading O.S's in the
market.

Drawbacks with Odbc Drivers:


1. These drivers must be installed on each and every machine where the application is executing from and
then the application, driver and data source should be manually configured with each other.
2. Odbc Drivers are initially designed for communication with Relational DB only.

OLE DB (Object Linking and Embedding, Database, sometimes written as OLEDB or OLE-DB), an API
designed by Microsoft, allows accessing data from a variety of data sources in a uniform manner. The API provides
a set of interfaces implemented using the Component Object Model (COM) and SQL. Microsoft originally intended
OLE DB as a higher-level replacement for, and successor to, ODBC, extending its feature set to support a wider variety
of non-relational databases, such as object databases and spreadsheets that do not necessarily implement SQL. OLE
DB is conceptually divided into consumers and providers. The consumers are the applications that need access to
the data, and the providers are the software components that implement the interface and thereby provide the data
to the consumer. An OLE DB provider is a software component enabling an OLE DB consumer to interact with a data
source. OLE DB providers are alike to ODBC drivers. OLE DB providers can be created to access such simple data
stores as a text file and spreadsheet, through to such complex databases as Oracle, Microsoft SQL Server, and many
others. It can also provide access to hierarchical data stores. These OLE DB Providers are introduced by Microsoft
around the year 1996.
1. It’s a collection of providers where these providers sit between the App's and Data Source to communicate
with each other and we require a separate provider for each data source.

142
2. Oledb Providers are designed for communication with relational & non-relational data source also i.e. it
provides support for communication with any Data Source.
3. Oledb Providers sits on server machine so they are already configured with data source and when we
connect with any data source they will help in the process of communication.
4. Oledb Providers are developed by using COM and Sql Languages, so they are also un-managed.
5. Microsoft introduced OLEDB as a replacement for ODBC for its Windows Systems.
6. Oledb is a pure Microsoft technology which works only on Windows Platform.

Things to remember while working with Odbc and Oledb:


1. Odbc and Oledb are un-managed or platform dependent.
2. Odbc and Oledb are not designed targeting any particular language i.e. they can be consumed by any
language like: C, CPP, Visual Basic, Visual CPP, Java, CSharp etc.

Note: If any language wants to consume Odbc Drivers or Oledb Providers they must use some built-in libraries of the
language in which we are developing the application without writing complex coding.

RDO’s and ADO’s in COM Language:


COM Language used RDO’s (Remote Data Objects) and ADO’s (ActiveX Data Objects) for data source
communication without having to deal with the comparatively complex ODBC or OLEDB API.

.NET Framework Providers:


The .NET Framework Data Provider for SQL Server uses its own protocol to communicate with SQL Server.
It is lightweight and performs well because it is optimized to access a SQL Server directly without adding an OLE DB
or ODBC layer and it supports SQL Server software version 7.0 or later. The .NET Framework Data Provider for Oracle
(Oracle Client) enables data access to Oracle data sources through Oracle client connectivity software. The data
provider supports Oracle client software version 8.1.7 or later.

ADO.Net:

143
It is a set of types that expose data access services to the .NET programmer. ADO.NET provides functionality
to developers writing managed code similar to the functionality provided to native COM developers by ADO.
ADO.NET provides consistent access to data sources such as Microsoft SQL Server, as well as data sources exposed
through OLE DB and XML. Data-sharing consumer applications can use ADO.NET to connect to these data sources
and retrieve, manipulate, and update data. It is an integral part of the .NET Framework, providing access to relational
data, XML, and application data. ADO.NET supports a variety of development needs, including the creation of front-
end database clients and middle-tier business objects used by applications or Internet browsers.

ADO.Net provides libraries for Data Source communication under the following namespaces:
• System.Data
• System.Data.Odbc
• System.Data.Oledb
• System.Data.SqlClient
• System.Data.OracleClient

Note: System.Data, System.Data.Odbc, System.Data.Oledb and System.Data.SqlClient namespaces are under the
assembly System.Data.dll whereas System.Data.OracleClient is under System.Data.OracleClient.dll assembly.

System.Data: types of this namespace are used for holding and managing of data on client machines. This
namespace contains following set of classes in it: DataSet, DataTable, DataRow, DataColumn, DataView,
DataRelation, etc.

System.Data.Odbc: types of this namespace can communicate with any Relational Data Source using Un-Managed
Odbc Drivers.

System.Data.Oledb: types of this namespace can communicate with any Data Source using Oledb Providers (Un-
Managed COM Providers).

System.Data.SqlClient: types of this namespace can purely communicate with Sql Server database only using
SqlClient Provider (Managed .Net Framework Provider).

System.Data.OracleClient: types of this namespace can purely communicate with Oracle database only using
OracleClient Provider (Managed .Net Framework Provider).

All the above 4 namespaces contains same set of types as following: Connection, Command, DataReader,
DataAdapter, Parameter and CommandBuilder etc, but here each class is referred by prefixing with Odbc, Oledb,
Sql and Oracle keywords before the class name to discriminate between each other as following:

OdbcConnection OdbcCommand OdbcDataReader OdbcDataAdapter OdbcCommandBuilder OdbcParameter

OledbConnection OledbCommand OledbDataReader OledbDataAdapter OledbCommandBuilder OledbParameter

SqlConnection SqlCommand SqlDataReader SqlDataAdapter SqlCommandBuilder SqlParameter

OracleConnection OracleCommand OracleDataReader OracleDataAdapter OracleCommandBuilder OracleParameter

144
Performing Operations on a DataSource: the operations we perform on a Data Source will be Select, Insert, Update
and Delete, and each and every operation we perform on a Data Source involves in 3 steps, like:
• Establishing a connection with the data source.
• Sending a request to Data Source by using SQL.
• Capturing the results given by the data source.

Establishing a Connection with Data Source:


It's a process of opening a channel for communication between Application and Data Source that is present
either on a local or remote machine to perform DB Operations and to open the channel for communication we use
Connection class.

Constructors of the Class:


Connection() Connection(string ConnectionString)

Note: ConnectionString is a collection of attributes that are required for connecting with a DataSource, those are:
• DSN
• Provider
• Data Source
• User Id and Password
• Integrated Security
• Database or Initial Catalog
• Extended Properties

DSN: this is the only attribute that is required if we want to connect with a data source by using Odbc Drivers and
by using this attribute we need to specify the DSN Name.

Provider: this attribute is required when we want to connect to the data source by using Oledb Providers. So by
using this attribute we need to specify the provider name based on the data source we want to connect with.
Oracle: Msdaora or ORAOLEDB.ORACLE Sql Server: SqlOledb
MS-Access or MS-Excel: Microsoft.Jet.Oledb.4.0 MS-Indexing Server: Msidxs

Data Source: this attribute is required to specify the server name if the data source is a database or else if the data
source is a file we need to specify path of the file and this attribute is required in case of any provider communication.

User Id and Password: This attribute is required to specify the credentials for connection with a database and this
attribute is required in case of any provider communication.
Oracle: Scott/tiger Sql Server: Sa/123

Integrated Security: this attribute is used while connecting with Sql Server Database only to specify that we want
to connect with the Server by using Windows Authentication and in this case we should not use User Id and Password
attributes and this attribute is required in case of any provider communication.

Database or Initial Catalog: these attributes are used while connecting with Sql Server Database only to specify the
name of DB we want to connect with and this attribute is required in case of any provider communication.

Extended Properties: this attribute is required only while connecting with MS-Excel using Oledb Provider.

145
List of attributes which are required in case of Odbc Drivers, Oledb and .Net Framework Providers:
Attribute ODBC Driver OLEDB Provider .NET Framework
Provider
DSN Yes No No
Provider No Yes No
Data Source No Yes Yes
User Id and Password No Yes Yes
Integrated Security* No Yes Yes
Database or Initial Catalog* No Yes Yes
Extended Properties** No Yes -
*Only for Sql Server **Only for Microsoft Excel
Connection String for SqlServer to connect by using different options:
OdbcConnection con = new OdbcConnection("Dsn=<Dsn Name>");
OledbConnection con = new OledbConnection("Provider=SqlOledb;Data Source=<Server Name>;
Database=<DB Name>;User Id=<User Name>;Password=<Pwd>");
SqlConnection con = new SqlConnection("Data Source=<Server Name>;Database=<DB Name>;
User Id=<User Name>;Password=<Pwd>");

Note: in case of Windows Authentication in place of User Id and Password attributes we need to use Integrated
Security = SSPI (Security Support Provider Interface).

Connection String for Oracle to connect by using different options:


OdbcConnection con = new OdbcConnection("Dsn=<Dsn Name>");
OledbConnection con = new OledbConnection("Provider=Msdaora (o)r ORAOLEDB.ORACLE;
Data Source=<Server Name>;User Id=<User Name>;Password=<Pwd>");
OracleConnection con = new OracleConnection("Data Source=<Server Name>;
User Id=<User Name>;Password=<Pwd>");

Connection String for MS-Excel to connect by using different options:


OdbcConnection con = new OdbcConnection("Dsn=<Dsn Name>");
OledbConnection con = new OledbConnection("Provider=Microsoft.Jet.Oledb.4.0;
Data Source=<Path of Excel Document>;Extended Properties=Excel 8.0”);
Members of Connection class:
1. Open(): a method which opens a connection with data source.
2. Close(): a method which closes the connection that is open.
3. State: an enumerated property which is used to get the status of connection.
4. ConnectionString: a property which is used to get or set a connection string that is associated with the
connection object.

Object of class Connection can be created in any of the following ways:


Connnection con = new Connection();
con.ConnectionString = "<connection string>";
or
Connection con = new Connection("<connection string>");

146
Testing the process of establishing a connection: open a new project of type Windows Forms Application, name it
as DBOperations and design the form as following:

Creating DSN for working with ODBC Drivers:


To work with Odbc Drivers first we need to configure the drivers installed on our machine with
corresponding Databases by creating a DSN (Data Source Name) and to do that go to Control Panel => Administrative
Tools => double click on Odbc DataSources to open ODBC Data Source Administrator window, click on Add button,
select a driver for Sql Server and click Finish button, which opens a window, in that enter the following details, Name:
SqlDsn, Description: Connects with Sql Server Database, Server: <Server Name>, click on Next button, select the
RadioButton “Using Sql Server Authentication”, enter the Login ID: <User Name>, Password: <Pwd>, click on Next
button, select the CheckBox “Change the default database to”, and select the Database to which we want to
configure with, click on Next button and Click on Finish button which displays a window showing the connection
details, click on Ok button which adds the DSN under ODBC Data Source Administrator window.

Again click on Add button, select a driver for Oracle and click Finish button, which opens a window, in it
enter the following details, Data Source Name: OraDsn, Description: Connects with Oracle Database, TNS Service
Name: <Server Name>, User ID: Scott/tiger, click on Ok button which adds the DSN under ODBC Data Source
Administrator window.

Again click on Add button, select a driver for Excel and click Finish button, which opens a window, in it enter
the following details, Data Source Name: ExcelDsn, Description: Connects with Microsoft Excel, Click on the “Select
Workbook” button and select the Excel file (.xls) from it’s physical location and clik on Ok button which adds the DSN
under ODBC Data Source Administrator window.

Now open the Solution Explorer, right click on References node under project and select “Add Reference”
which opens ‘’Reference Manager” dialog box, in that on the LHS under Assemblies option select Framework, now
on the RHS select “System.Data.OracleClient.dll” assembly, click Ok and then write the following code:

using System.Data.Odbc; using System.Data.OleDb; using System.Data.SqlClient; using System.Data.OracleClient;


Under “Connect with Sql Server using Odbc Driver” Button Click:
OdbcConnection con = new OdbcConnection("Dsn=SqlDsn");
con.Open(); MessageBox.Show("Connection with Sql Server using Odbc Driver is: " + con.State);
con.Close(); MessageBox.Show("Connection with Sql Server using Odbc Driver is: " + con.State);
Under “Connect with Sql Server using OLEDB Provider” Button Click:
OleDbConnection con = new OleDbConnection();
Con.ConnectionString = “Provider=SqlOledb;User Id=Sa;Password=123;Data Source=Server;Database=Master");
ocon.Open(); MessageBox.Show("Connection with Sql Server using Oledb Provider is: " + con.State);
ocon.Close(); MessageBox.Show("Connection with Sql Server using Oledb Provider is: " + con.State);

147
Under “Connect with Sql Server using .NET Framework Provider” Button Click:
SqlConnection con = new SqlConnection("Data Source=Server;User Id=Sa;Password=123;Database=Master");
con.Open(); MessageBox.Show("Connection with Sql Server using Framework Provider is: " + con.State);
con.Close(); MessageBox.Show("Connection with Sql Server using Framework Provider is: " + con.State);
Under “Connect with MS Excel using Odbc Driver” Button Click:
OdbcConnection con = new OdbcConnection("Dsn=ExcelDsn");
con.Open(); MessageBox.Show("Connection with Excel using Odbc Driver is: " + con.State);
con.Close(); MessageBox.Show("Connection with Excel using Odbc Driver is: " + con.State);
Under “Connect with MS Excel using Oledb Provider” Button Click:
OleDbConnection con = new OleDbConnection(
"Provider=Microsoft.Jet.Oledb.4.0;Data Source=C:\\ExcelDocs\\School.xls;Extended Properties=Excel 8.0");
con.Open(); MessageBox.Show("Connection with Excel using Oledb Provider is: " + con.State);
con.Close(); MessageBox.Show("Connection with Excel using Oledb Provider is: " + con.State);
Under “Connect with Oracle using Odbc Driver” Button Click:
OdbcConnection con = new OdbcConnection("Dsn=OraDsn");
con.Open(); MessageBox.Show("Connection with Oracle using Odbc Driver is: " + con.State);
con.Close(); MessageBox.Show("Connection with Oracle using Odbc Driver is: " + con.State);
Under “Connect with Oracle DB using Oledb Provider” Button Click:
OleDbConnection con = new OleDbConnection("Provider=OraOledb.Oracle;User Id=Scott;Password=tiger");
con.Open(); MessageBox.Show("Connection with Oracle using Oledb Provider is: " + con.State);
con.Close(); MessageBox.Show("Connection with Oracle using Oledb Provider is: " + con.State);
Under “Connect with Oracle using .NET Framework Provider” Button Click:
OracleConnection con = new OracleConnection("Data Source=Server;User Id=Scott;Password=tiger");
con.Open(); MessageBox.Show("Connection with Oracle using .NET Framework Provider is: " + con.State);
con.Close(); MessageBox.Show("Connection with Oracle using .NET Framework Provider is: " + con.State);
Sending request to Data Source by using SQL:
In this process we send a request to Data Source by specifying the type of action we want to perform by
using an Sql Statement like Select, Insert, Update, and Delete or by calling a Stored Procedure present under the
Data Source. To send and execute Sql Statements or call Stored Procedures in Data Source we use Command class.

Constructors of the class:


Command()
Command(string CommandText, Connection con)
Note: CommandText means it can be any SQL Statement like Select or Insert or Update or Delete Statements or
Stored Procedure Name, whereas “Connection” refers to instance of Connection class created in 1st step.

Properties of Command Class:


1. Connection: sets or gets the connection object associated with command object.
2. CommandText: sets or gets the Sql statement or SP name associated with command object.
3. CommandType: sets or gets whether Command is configured to execute a SQL Statement [default] or S.P.

The object of class Command can be created in any of the following ways:
Command cmd = new Command(); cmd.Connection = <con>; cmd.CommandText = "<Sql Stmt or SP Name>";
or
Command cmd = new Command("<Sql Stmt or SP Name>", <con>);

148
Methods of Command class:
• ExecuteReader() => DataReader
• ExecuteScalar() => object
• ExecuteNonQuery() => int

Note: after creating object of Command class we need to call any of the execute methods to execute the stmt’s.

Use ExecuteReader() method when we want to execute a Select Statement that returns data as rows and
columns. The method returns an object of class DataReader which holds data that is retrieved from data source in
the form of rows and columns.

Use ExecuteScalar() method when we want to execute a Select Statement that returns a single value result.
The method returns result of the query in the form of an object.

Use ExecuteNonQuery() method when we want to execute any SQL statement other than select, like Insert
or Update or Delete etc. The method returns an integer that tells the no. of rows affected by the statement.

Note: The above process of calling a suitable method to capture results is our third step i.e. capturing the results.
Accessing data from a DataReader: DataReader is a class which can hold data in the form of rows and columns, to
access data from DataReader it provides the following members:
1. GetName(int ColumnIndex) => string
Returns name of the column for given index position.
2. Read() => bool
Moves record pointer from current location to next row and returns a Boolean value which tells whether the row to
where it moved contains any data or not, which will be true if data is present or false if data is not present.
3. GetValue(int ColumnIndex) => object
4. Indexer[int ColumnIndex] => object
5. Indexer[string ColumnName] => object
All the 3 are used for retrieving column values from the row to which pointer was pointing by specifying the Column
Index or Column Name.
6. FieldCount => int
This property returns the no. of columns fetched into the DataReader
7. NextResult() => bool
Moves record pointer from current table to next table and returns a Boolean value which tells whether the location
to which it moved contains a table or not, which will be true if present or false if not present.
Add a new Windows Form under the project and design it as following:

using System.Data.OracleClient;
Declarations: OracleConnection con; OracleCommand cmd; OracleDataReader dr;

149
Under Form Load:
con = new OracleConnection(“User Id=Scott;Password=tiger;Data Source=Server”);
cmd = new OracleCommand(“Select Deptno, Dname, Loc From Dept”, con); con.Open(); dr = cmd.ExecuteReader();
label1.Text = dr.GetName(0); label2.Text = dr.GetName(1); label3.Text = dr.GetName(2); ShowData();
private void ShowData() {
if(dr.Read()) {
textBox1.Text = dr.GetValue(0).ToString();
textBox2.Text = dr[1].ToString();
textBox3.Text = dr[“Loc”].ToString();
}
else { MessageBox.Show(“You are alredy at last record of the table.”, “Warning”); }
}
Under Next Button: ShowData();
Under Close Button: if(con.State != ConnectionState.Closed) { con.Close(); } this.Close();
Working with Sql Server
Sql Server is a collection of databases, where a database is again collection of various objects like tables,
views, procedures etc.; users of Sql Server can be owner of 1 or more databases at a time, so while connecting with
Sql Server from a .NET application within the connection string we need to specify name of the database we want
to connect either by using Database or Initial Catalog attributes.

Sql Server provides 2 different modes of authentication for connecting with the DB Server those are:
1. Windows Authentication
2. Sql Server Authentication
When a user connects through windows authentication, Sql Server validates the account name and
password using the windows principal token in the operating system; this means that the user identity is confirmed
by windows, Sql Server does not ask for the password and does not perform the identity validation. When using Sql
Server authentication, logins are created in Sql Server that is not based on windows user accounts, both the user
name and password are created by using Sql Server and stored in Sql Server database. Users connecting with Sql
Server authentication must provide their credentials every time they connect with DB Server.

Note: if we want to connect using windows authentication mode, within the connection string in the place of User
Id and Password attributes use “Integrated Security=SSPI” attributes.

Connecting String for Sql Server Authentication:


“Provider=SqlOledb;User Id=<User Name>;Password=<Pwd>;Database=<DB Name>[;Data Source=<Server Name>]”
Connecting String for Windows Authentication:
“Provider=SqlOledb;Integrated Security=SSPI;Database=<DB Name>[;Data Source=<Server Name>]”

Creating a database on Sql Server:


Open Sql Server Management Studio and provide the authentication details to login. Once the studio is
opened in the LHS we find a window “Object Explorer”, in that right click on the node Databases, select “New
Database” that opens a window asking for the name, enter the name as: CSDB, click ok which adds the database
under databases node. Now expand the database node, right click on Tables node and select “New Table” which
opens a window asking for column names and data types enter the following:
Eno (Int), Ename (Varchar), Job (Varchar), Salary (Money), Photo (Image), Status (Bit) => Not Null

150
Now select Eno Column, right click on it and select the option “Set Primary Key” and make it as an identity
or key column of the table. Select Status column, go to its properties in the bottom and set “Default value or Binding”
property as 1, which takes the default value for status column as true. Click on the save button at top of the studio
which will prompt for table name enter name as “Employee” and click Ok which adds the table under tables node.
Now right click on the table created and select “Edit” which opens a window, enter some data in to the table ignoring
Photo and Status columns. Close the studio.

Now ddd a new form in the project and design it as following and write the below code:

Set Read-only Property as True

Set Enabled Property as False

using System.Data.SqlClient;
Declarations: SqlConnection con; SqlCommand cmd; SqlDataReader dr; string SqlStr;
Under Form Load:
con = new SqlConnection("User Id=Sa;Password=123;Database=CSDB;Data Source=Server");
cmd = new SqlCommand(); cmd.Connection = con; con.Open(); LoadData();
private void LoadData() {
cmd.CommandText = "Select Eno, Ename, Job, Salary, Status From Employee Order By Eno";
dr = cmd.ExecuteReader(); ShowData();
}
private void ShowData() {
if (dr.Read()) {
textBox1.Text = dr[0].ToString();
textBox2.Text = dr[1].ToString();
textBox3.Text = dr[2].ToString();
textBox4.Text = dr[3].ToString();
checkBox1.Checked = Convert.ToBoolean(dr[4]);
}
else { MessageBox.Show("No data exists."); }
}
Under Next Button: ShowData();
Under New Button:
textBox1.Text = textBox2.Text = textBox3.Text = textBox4.Text = ""; checkBox1.Checked = false;
dr.Close(); cmd.CommandText = "Select IsNull(Max(Eno), 1000) + 1 From Employee";
textBox1.Text = cmd.ExecuteScalar().ToString(); btnInsert.Enabled = true; textBox2.Focus();
private void ExecuteDML() {
DialogResult d = MessageBox.Show(“Are you sure of executing the below Sql Statement?\n\n" + SqlStr,
"Confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Question);

151
if (d == DialogResult.Yes) {
cmd.CommandText = SqlStr;
int count = cmd.ExecuteNonQuery();
if (count > 0) { MessageBox.Show("Statement executed successfully"); }
else { MessageBox.Show("Statement failed execution"); }
LoadData();
}
}
Under Close Button: if (con.State != ConnectionState.Closed) { con.Close(); } this.Close();
Under Insert Button:
SqlStr = "Insert Into Employee (Eno, Ename, Job, Salary, Status) Values(" + textBox1.Text + ", '" + textBox2.Text + "',
'" + textBox3.Text + "', " + textBox4.Text + ", " + Convert.ToInt32(checkBox1.Checked) + ")";
or
SqlStr = String.Format("Insert Into Employee (Eno, Ename, Job, Salary, Status) Values({0}, '{1}', '{2}', {3}, {4})",
textBox1.Text, textBox2.Text, textBox3.Text, textBox4.Text, Convert.ToInt32(checkBox1.Checked));
or
SqlStr = $"Insert Into Employee (Eno, Ename, Job, Salary, Status) Values ({textBox1.Text}, '{textBox2.Text}',
'{textBox3.Text}', {textBox4.Text} , {Convert.ToInt32(checkBox1.Checked)})";
or
SqlStr="Insert Into Employee (Eno, Ename, Job, Salary, Status) Values (@Eno, @Ename, @Job, @Salary, @Status)";
cmd. Parameters.Clear(); cmd.Parameters.AddWithValue("@Eno", textBox1.Text);
cmd.Parameters.AddWithValue("@Ename", textBox2.Text);
cmd.Parameters.AddWithValue("@Job", textBox3.Text);
cmd.Parameters.AddWithValue("@Salary", textBox4.Text);
cmd.Parameters.AddWithValue("@Status", checkBox1.Checked);

ExecuteDML(); btnInsert.Enabled = false;


Under Update Button:
SqlStr = "Update Employee Set Ename='" + textBox2.Text + "', Job='" + textBox3.Text + "', Salary=" + textBox4.Text +
", Status=" + Convert.ToInt32(checkBox1.Checked) + " Where Eno=" + textBox1.Text;
or
SqlStr = String.Format("Update Employee Set Ename='{0}', Job='{1}', Salary={2}, Status={3} Where Eno={4}",
textBox2.Text, textBox3.Text, textBox4.Text, Convert.ToInt32(checkBox1.Checked), textBox1.Text);
or
SqlStr = $"Update Employee Set Ename='{textBox2.Text}', Job='{textBox3.Text}', Salary={textBox4.Text},
Status={Convert.ToInt32(checkBox1.Checked)} Where Eno={textBox1.Text}";
or
SqlStr = "Update Employee Set Ename=@Ename, Job=@Job, Salary=@Salary, Status=@Status Where Eno=@Eno";
cmd. Parameters.Clear(); cmd.Parameters.AddWithValue("@Ename", textBox2.Text);
cmd.Parameters.AddWithValue("@Job", textBox3.Text);
cmd.Parameters.AddWithValue("@Salary", textBox4.Text);
cmd.Parameters.AddWithValue("@Status", checkBox1.Checked);
cmd.Parameters.AddWithValue("@Eno", textBox1.Text);

dr.Close(); ExecuteDML();

152
Under Delete Button:
SqlStr = "Delete From Employee Where Eno=" + textBox1.Text;
or
SqlStr = String.Format("Delete From Employee Where Eno={0}", textBox1.Text);
or
SqlStr = $"Delete From Employee Where Eno={textBox1.Text}";
or
SqlStr = "Delete From Employee Where Eno=@Eno";
cmd. Parameters.Clear(); cmd.Parameters.AddWithValue("@Eno", textBox1.Text);

dr.Close(); ExecuteDML();
Accessing data from Excel document into .Net Application
MS Excel is a file system which stores data in the form of rows and columns same as a database table. An
Excel document is referred as Work Book that contains Work Sheets in it, work books are considered as databases
and work sheets are considered as tables. First row of work sheet can store column names.

Creating an Excel Document:


Open Microsoft Office Excel and by default the document contains 3 work sheets in it. Now in the first row
of the sheet1 enter column names for Student table as Sno, Sname, Class, Fees and from the second row enter few
records in it. Now in bottom of the document change the sheet name Sheet1 as Student, click “Save” and under
“Save as type” choose “Excel 97 – 2003 Workbook”, name the document as “School.xls” and save it in your desired
location.

Connecting with Excel document from .Net Application:


We can connect with Excel documents from .Net application by using Drivers or Providers also. To connect
with drivers first we need to configure ODBC driver for Excel. To configure driver go to Control Panel =>
Administrative Tools => Data Sources (ODBC), click on it to open ODBC Data Source Administrator window, Click Add
button, select Microsoft Excel (*.xls) driver, Click finish and Enter the following details, Data Source Name:
“ExcelDsn”, Description: “Connects with Microsoft Excel”, and click on Select Workbook button to choose the
School.xls document from it physical location and click on the Ok button which adds the DSN under ODBC Data
Source Administrator window. Now add a new windows form in the project and design it as following:

using System.Data.Odbc;
Declarations: OdbcConnection con; OdbcCommand cmd; OdbcDataReader dr; string SqlStr;
Under Form Load:
con = new OdbcConnection("Dsn=ExcelDsn;ReadOnly=0");
cmd = new OdbcCommand(); cmd.Connection = con; con.Open(); LoadData();
label1.Text=dr.GetName(0); label2.Text=dr.GetName(1);
label3.Text=dr.GetName(2); label4.Text=dr.GetName(3);

153
private void LoadData() {
cmd.CommandText = "Select * From [Student$]"; dr = cmd.ExecuteReader(); ShowData();
}
private void ShowData() {
if (dr.Read()) {
textBox1.Text = dr[0].ToString(); textBox2.Text = dr[1].ToString();
textBox3.Text = dr[2].ToString(); textBox4.Text = dr[3].ToString();
}
else
MessageBox.Show("No data exists.”);
}
Under Next Button: ShowData();
Under Clear Button:
textBox1.Text=textBox2.Text=textBox3.Text=textBox4.Text = ""; textBox1.Focus();
private void ExecuteDML() {
dr.Close(); cmd.CommandText = SqlStr;
if (cmd.ExecuteNonQuery() > 0) { MessageBox.Show("Insert Or Update operation was successful."); }
else {MessageBox.Show("Insert or Update operation failed."); }
LoadData();
}
Under Insert Button: SqlStr = String.Format(“Insert Into [Student$] Values ({0}, ‘{1}’ {2}, {3})”, textBox1.Text,
textBox2.Text, textBox3.Text, textBox4.Text); dr.Close(); ExecuteDML();
Under Update Button: SqlStr = String.Format(“Update [Student$] Set Sname='{0}’, Class={1}, Fees={2} where
Sno={3}”, textBox2.Text, textBox3.Text, textBox4.Text, textBox1.Text); ExecuteDML();
Under Close Button: if (con.State != ConnectionState.Closed) { con.Close(); } this.Close();
Connecting with Excel using OLEDB Provider: to connect with Excel documents using OLEDB Provider, Connection
String should be as following:
"Provider=Microsoft.Jet.Oledb.4.0;Data Source=<path of the excel file>;Extended Properties=Excel 8.0"

Note: OdbcConnection class opens connection with Excel Document in read only mode so if we want to perform any
manipulations to data in the document we need to open it in read/write mode by setting the attribute “ReadOnly=0”
under the connection string, whereas OledbConnection will open the document in read/write mode only so no need
of using readonly attribute there.
DataReader: it's a class designed for holding the data on client machines in the form of Rows and Columns.

Features of DataReader:
1. Faster access to data from the Data Source because it is “Connection Oriented”.
2. Can hold multiple tables in it at a time and to load multiple tables into a DataReader pass multiple Select
Statements as “CommandText” to command separated by a semi-colon.

E.g.: Command cmd = new Command("Select * From Student;Select * From Teacher", con);
DataReader dr = cmd.ExecuteReader();

Note: use NextResult() method on data reader object to navigate from current table to next table.
dr.NextResult() => bool

154
Drawbacks of DataReader:
1. As it is connection oriented requires a continuous connection with data source while we are accessing the
data, so there are chances of performance degradation if there are more no. of clients accessing data at the
same time.
2. It gives forward only access to the data i.e. allows going either to next record or table but not to previous
record or table.
3. It is a read only object which will not allow any changes to data that is present in it.
Dis-Connected Architecture: ADO.Net supports 2 different models for accessing data from Data Sources:

1. Connection Oriented Architecture


2. Disconnected Architecture

In the first case we require a continuous connection with Data Source for accessing data from it and in this
case we use DataReader class for holding data on client machines, where as in the 2nd case we don’t require a
continuous connection with Data Source for accessing the data from it i.e. we require a connection only for loading
data from Data Source and in this case we use DataSet class for holding data on client machines.
Working with DataSet
DataSet: It's a class present under System.Data namespace designed for holding and managing of the data on client
machines apart from DataReader. DataSet class provides the following features:

1. DataSet is also capable of holding multiple tables like a DataReader whereas in case of DataSet those tables
can be loaded from different data sources.
2. It is designed in disconnected architecture which requires a connection just for loading data but not for
holding and accessing the data.
3. It provides scrollable navigation to data which allows us to move in any direction i.e. either top to bottom
or bottom to top.
4. It is updatable i.e. changes can be made to data present in it and those changes can be sent back to DB for
update.
5. It provides options for searching and sorting of data that is present under it.
6. It provides options for establishing relations between the tables that are present under it.

Loading Data into DataSet's: The class which is responsible for loading data into DataReader from a DataSource is
Command, in the same way DataAdapter class is required for communication between DataSource and DataSet.
DataSource <= Command => DataReader
DataSource <=> DataAdapter <=> DataSet

Note: DataAdapter is internally a collection of 4 commands like “SelectCommand”, “InsertCommand”,


“UpdateCommand” and “DeleteCommand” where each command is an instance of Command class, and by using
these commands DataAdapter will perform Select, Insert, Update and Delete operations on a table.

Constructors of DataAdapter class:


DataAdapter()
DataAdapter(Command SelectCmd)
DataAdapter(string SelectCommandText, Connection con)
DataAdapter(string SelectCommandText, string ConnectionString)

155
Note: Select Command Text means it can be a Select Stmt or a Stored Procedure which contains a Select Stmt.
Instance of DataAdapter class can be created in any of the following ways:
Connection con = new Connection(“<Connection String>”);
Command cmd = new Command(“<Select Stmt or SP Name>”, con);
DataAdapter da = new DataAdapter();
da.SelectCommand = cmd;
Or
Connection con = new Connection(“<Connection String>”);
Command cmd = new Command(“<Select Stmt or SP Name>”, con);
DataAdapter da = new DataAdapter(cmd);
Or
Connection con = new Connection(“<Connection String>”);
DataAdapter da = new DataAdapter(“<Select Stmt or SPName>”, con);
or
DataAdapter da = new DataAdapter(“<Select Stmt or SPName>”, “<Connection String>”);

Properties of DataAdapter:
1. SelectCommand
2. InsertCommand
3. UpdateCommand
4. DeleteCommand

Methods of DataAdapter:
1. Fill(DataSet ds, string tableName)
2. Update(DataSet ds, string tableName)

Fill method is used for loading data from DataSource into the DataSet and Update method is used for
updating any changes made in the DataSet back to DataSource:

Fill: DataSource => DataAdapter => DataSet


Update: DataSource <= DataAdapter <= DataSet

When we call Fill method on DataAdapter class, then following actions will take place internally:
• DataAdapter will open a connection with the Data Source.
• Executes the SelectCommand present in it on the DataSource and loads data from table to DataSet.
• Closes the connection.

156
Once the execution of Fill method is completed data gets loaded into the DataSet as below:

As we are discussing DataSet is updatable, we can make changes to the data that is loaded into it like adding,
and modifying and deleting of records and after making changes to data in DataSet if we want to send those changes
back to DataSource we need to call Update method on DataAdapter, which performs the following:
• DataAdapter will re-open the connection with Data Source.
• Changes that are made to data in DataSet will be sent back to corresponding table, where in this process it
will make use of Insert, Update and Delete commands of DataAdapter.
• Closes the connection.

Once Update method execution is completed data gets re-loaded into DataSet as below with all unchanged rows:

Accessing data from DataSet: DataReader’s provides pointer based access to the data, so we can get data only in a
sequential order whereas DataSet provides index based access to the data, so we can get data from any location
randomly. DataSet is a collection of tables where each table is represented as a class DataTable and identified by its
index position or name. Every DataTable is again collection of Rows and collection of Columns where each row is
represented as a class DataRow and identified by its index position and each column is represented as a class
DataColumn and identified by its index position or name.
• Accessing a DataTable from DataSet: <dataset>.Tables[index] or <dataset>.Tables[name]
E.g.: ds.Tables[0] or ds.Tables["Employee"]

• Accessing a DataRow from DataTable: <datatable>.Rows[index]


E.g.: ds.Tables[0].Rows[0]

• Accessing a DataColumn from DataTable: <datatable>.Columns[index] or <datatable>.Columns[name]


E.g.: ds.Tables[0].Columns[0] or ds.Tables[0].Columns["Eno"]

• Accessing a Cell from DataTable: <datatable>.Rows[row][col]


E.g.: ds.Tables[0].Rows[0][0] or ds.Tables[0].Rows[0]["Eno"]

157
Add a new form in the project, design it as below, and then add reference of Microsoft.VisualBasic assembly
from Framework tab of add reference window and write the code:

Set Read-only Property as True

Set Enabled Property as False

using System.Data.SqlClient; using static Microsoft.VisualBasic.Interaction;


Declarations: SqlConnection con; SqlDataAdapter da; DataSet ds; int rno = 0;
Under Form Load:
con = new SqlConnection("User Id=Sa;Password=123;Database=CSDB;Data Source=Server");
da = new SqlDataAdapter("Select Eno, Ename, Job, Salary From Employee Order By Eno", con);
da.MissingSchemaAction = MissingSchemaAction.AddWithKey;
ds = new DataSet(); da.Fill(ds, "Employee"); ShowData();
private void ShowData() {
if (ds.Tables[0].Rows[rno].RowState != DataRowState.Deleted) {
textBox1.Text=ds.Tables[0].Rows[rno][0].ToString(); textBox2.Text=ds.Tables[0].Rows[rno][1].ToString();
textBox3.Text=ds.Tables[0].Rows[rno][2].ToString(); textBox4.Text=ds.Tables[0].Rows[rno][3].ToString();
}
else
MessageBox.Show("Deleted rows data cannot be accessed.");
}
Under First Button: rno = 0; ShowData();
Under Prev Button:
if (rno > 0) {
rno -= 1; ShowData();
}
else
MessageBox.Show("First record of the table.");
Under Next Button:
if (rno < ds.Tables[0].Rows.Count - 1) {
rno += 1; ShowData();
}
else { MessageBox.Show("Last record of the table."); }
Under Last Button: rno = ds.Tables[0].Rows.Count - 1; ShowData();
Under New Button:
textBox1.Text = textBox2.Text = textBox3.Text = textBox4.Text = “”;
int Index = ds.Tables[0].Rows.Count - 1; //Finding the index position of last record.
int Eno = Convert.ToInt32(ds.Tables[0].Rows[Index][0]) + 1; //Finding the Eno of last record and adding 1 to it.
textBox1.Text = Eno.ToString(); btnInsert.Enabled = true; textBox2.Focus();

158
Adding a DataRow to DataTable of DataSet:
To add a DataRow to the DataTable of DataSet adopt the following process:
1. Create a new row by calling the NewRow method on DataTable which creates a new row with the same
structure of the DataTable.
2. Assign values to the new row by treating it as a single dimensional array.
3. Call the Rows.Add method on DataTable and add the row to DataRowCollection.
Under Insert Button:
DataRow dr = ds.Tables[0].NewRow();
dr[0] = textBox1.Text; dr[1] = textBox2.Text; dr[2] = textBox3.Text; dr[3] = textBox4.Text;
ds.Tables[0].Rows.Add(dr); rno = ds.Tables[0].Rows.Count - 1; btnInsert.Enabled = false;
MessageBox.Show("DataRow added to DataTable of DataSet.");
Updating a DataRow in DataTable of DataSet:
To update an existing DataRow in DataTable of DataSet we need to re-assign the modified values back to
the DataRow in data table, so that the old values get modified with new values.
Under Update Button:
ds.Tables[0].Rows[rno]["Ename"] = textBox2.Text; ds.Tables[0].Rows[rno]["Job"] = textBox3.Text;
ds.Tables[0].Rows[rno][ "Salary"] = textBox4.Text; MessageBox.Show("DataRow updated in DataTable of
DataSet.");
Deleting a DataRow from DataTable of DataSet:
To delete an existing DataRow in DataTable of DataSet call Delete() method pointing to the row that has
to be deleted on DataTable.
Under Delete Button:
ds.Tables[0].Rows[rno].Delete(); MessageBox.Show("DataRow deleted from DataTable of DataSet.");
Saving changes made in DataTable of DataSet back to DataBase:
If we want to save changes made in DataTable of DataSet back to Database we need to call Update method
on DataAdapter by passing the DataSet which contains modified values as a parameter. If Update method of
DataAdapter has to work it should contain 3 commands under it i.e. Insert, Update and Delete and these 3
commands have to be written by the programmers explicitly or can be generated implicitly with the help of
CommandBuilder class. CommandBuilder class constructor if given with DataAdapter that contains a
SelectCommand in it will generate the remaining 3 commands.
Note: CommandBuilder can generate update and delete commands for a given select command only if the database
table contains Primary Key Constraint on it.
Under Save To DB Button:
SqlCommandBuilder cb = new SqlCommandBuilder(da);
da.Update(ds, "Employee"); MessageBox.Show("Data saved to DB Server");
Under Close Button: this.Close();
Searching for a DataRow in DataTable of DataSet:
To search for a DataRow in DataTable of DataSet call Find method on DataRowCollection this searches for
the DataRow on Primary Key Column(s) of table and returns a Row.
Find(Object key) => DataRow Find(Object[] keys) => DataRow
Use the first method if the primary key constraint is present on a single column or else use the second
method if it is a composite primary key.

Note: if the Find method has to work we need to first load the Primary Key information of database table into DataSet
by setting the property value as “AddWithKey” for MissingSchemaAction of DataAdapter.

159
Under Search Button:
int Eno;
string value = InputBox("Enter Employee No. to search", "Employee Search", "", 150, 150);
if (int.TryParse(value, out Eno)) {
DataRow dr = ds.Tables[0].Rows.Find(Eno);
if (dr != null) {
rno = ds.Tables[0].Rows.IndexOf(dr);
textBox1.Text = dr[0].ToString(); textBox2.Text = dr[1].ToString();
textBox3.Text = dr[2].ToString(); textBox4.Text = dr[3].ToString();
}
else { MessageBox.Show("No Employee exists with given Employee No."); }
}
else { MessageBox.Show("Employee No must be an integer value."); }
Configuration Files
While developing applications if there are any values in application which requires changes in future, should
not be hard coded i.e. should not be maintained as static values within the application, because if any changes are
required for those values in future client will not be able to make changes because they will not have the source
code of application for modification. To overcome this problem we need to identify those values and put them under
a special file known as Configuration File, it’s an XML file which stores values in it in the form of Key/Value pairs. The
values that are present under configuration file can be read from applications in runtime. We store values like
Company Name, Address, Phone No, Fax No, connection strings etc., in these files. When an application is installed
on the client machines along with it the configuration file also will be installed there and because the configuration
file is a text file clients can edit those files and make modification to the values under them at any time and those
values will be taken into the application for execution.

Storing values under configuration file: By default the file comes with a tag <configuration></configuration> and all
the values must be present under this tag only in the form of different sections as following:

<appSettings>
<add key="CompanyName" value="Naresh I Technologies"/>
<add key="Address" value="Ameerpet, Hyderabad - 38"/>
<add key="Phone" value="23746666"/>
<add key="Email" value="[email protected]"/>
</appSettings>

Reading configuration file values from applications: to read configuration file values from applications we are
provided with a class ConfigurationManager within the namespace System.Configuration present under the
assembly System.Configuration.dll. To consume the class we need to first add reference of the assembly using the
“Add Reference” window and we find the assemblies under Framework Tab, after adding the reference of assembly
import the namespace and read the values as following:
ConfigurationManager.AppSettings.Get(string key) => string (returns the value for given key as string)

To test the above process add a configuration file in the project and store values in it as shown above within
the <configuration>/<configurations> tags. Now add a new form in the project place a button on it setting the Text
as “Read Configuration Values” and write the following code in code view:

160
using System.Configuration;
Under Read Configuration Values Button:
string cname = ConfigurationManager.AppSettings.Get("CompanyName");
string addr = ConfigurationManager.AppSettings.Get("Address");
string phone = ConfigurationManager.AppSettings.Get("Phone");
string email = ConfigurationManager.AppSettings.Get("Email");
MessageBox.Show(cname + “\n” + addr + “\n” + phone + “\n” + email);
Storing Connection Strings under configuration files:
We can store the connection string values also in configuration files so that we don’t require to specify the
connection strings in all forms and whenever we want to change it we can make the change directly under the
configuration file. To store connection strings in the configuration file we are provided with a tag
<connectionStrings> same as <appSettings> tag, so we can maintain the connection string values in the configuration
file under <configuration> tag as following:

<connectionStrings>
<add name="OConStr" connectionString="User Id=Scott;Password=tiger;Data Source=Server"
providerName=" ORAOLEDB.ORACLE"/>
<add name="SConStr" connectionString ="User Id=Sa;Password=123;Database=CSDB;
Data Source=Server" providerName="SqlOledb"/>
</connectionStrings>

Note: we can read the connection string values from our application as following:
string oconstr = ConfigurationManager.ConnectionStrings["OConStr"].ConnectionString;
string oprovider = ConfigurationManager.ConnectionStrings["OConStr"].ProviderName;
string sconstr = ConfigurationManager.ConnectionStrings["SConStr"].ConnectionString;
string sprovider = ConfigurationManager.ConnectionStrings["SConStr"].ProviderName;
DataGridView: this control is used for displaying the data in the form of a table i.e. rows and columns. To display
data in the control first we need to bind the DataTable of DataSet to the DataGridView control by using its
DataSource property as following:
dataGridView1.DataSource = <DataTable>

DataGridView control has a specialty i.e. changes performed to data in it gets reflected directly to the data
of DataTable to which it was bound, so that we can update dataset back to database directly.

To test this process add a new Form in the project and place a DataGridView control on it setting its dock
property as top. Now place 2 buttons on the form setting the text as “Save” and “Close” and write the code:

161
using System.Configuration; using System.Data.SqlClient;
Declarations:
DataSet ds; SqlDataAdapter da;
Under Form Load:
string ConStr = ConfigurationManager.ConnectionStrings["SConStr"].ConnectionString;
da = new SqlDataAdapter("Select Eno, Ename, Job, Salary From Employee Order By Eno", ConStr);
ds = new DataSet(); da.Fill(ds, "Employee"); dataGridView1.DataSource = ds.Tables[0];
Under Save Button:
SqlCommandBuilder cb = new SqlCommandBuilder(da); da.Update(ds, "Employee");
MessageBox.Show("Data saved to DB Server.", “Confirmation”);
Under Close Button: this.Close();
Loading multiple tables into DataSet:
A DataSet can hold any no. of tables in it and if we want to load multiple tables into a Dataset we have 2 different
approaches.
1. Using a single DataAdapter we can load any no. of tables into the DataSet by changing the SelectCommand
of DataAdapter each time after calling Fill and loading a table into DataSet. In this approach if we want to
make any changes to the data of dataset and send it back to database we can do it on last table of the
dataset only because an adapter can hold all the 4 commands only for a single table i.e. for the last
SelectCommand we have given only the required insert, update and delete commands will be generated by
CommandBuilder class.

2. Using a separate DataAdapter for each table being loaded into DataSet we can load multiple tables. In this
approach it will be possible to update all the tables data back to the database because each table is using
an individual DataAdapter that will hold the required insert, update and delete commands for a table and
more over, here each table can also be loaded from a different data source i.e. 1 table from Oracle 1 table
from Sql Server etc.
DataView: Just like we have Views in SQL, we have DataView class in ADO.Net. A DataView class object represents
a customized view of DataTable object. Operations like Sorting; Searching can be performed on a DataView object.
In scenarios like retrieval of a subset of data from a DataTable, we can make use of DataView to get this data. Note
that the DefaultView property of a DataTable returns the default data view for the DataTable.

Using a DataView for filtering and sorting the data under DataTable:
Step1: Create a reference of class DataView by calling DefaultView property on the DataTable which will return a
DataView reference with same structure of the table on which the property is called.
DataView dv = ds.Tables[“Emp”].DefaultView;

Step2: Specify a condition for filter by making use of the RowFilter property or specify a column for sorting the data
using Sort property of DataView class.
dv.RowFilter = “Job = ‘Manager’”; dv.RowFilter = “Salary > 2500”;
dv.RowFilter = “Job = ‘Manager’ And Salary > 2500”; dv.RowFilter = “Job = ‘Manager’ Or Salary > 2500”;

dv.Sort = “Salary”; or dv.Sort = “Salary Desc”; or dv.Sort = “Salary, Comm”; or dv.Sort = “Salary, Comm Desc”;
Loading multiple tables into a DataSet using single DataAdapter and filtering the data using DataView:
Add a new form in the project, place a ComboBox control at top center, place a DataGridView control below
and write the following code:

162
using System.Configuration; using System.Data.SqlClient;
Declarations:
SqlDataAdapter da; DataSet ds; bool Flag = false;
Under Form Load:
string ConStr = ConfigurationManager.ConnectionStrings["SConStr"].ConnectionString;
ds = new DataSet(); da = new SqlDataAdapter(“Select * from Dept”, ConStr); da.Fill(ds, “Dept”);
da.SelectCommand.CommandText = “Select * From Emp”; da.Fill(ds, “Emp”);
comboBox1.DataSource = ds.Tables[“Dept”]; comboBox1.DisplayMember = “Dname”;
comboBox1.ValueMember = “Deptno”; comboBox1.SelectedIndex = -1;
comboBox1.Text = “-Select Department-”; dataGridView1.DataSource = ds.Tables[“Emp”]; Flag = true;
Under ComboBox SelectedIndexChanged:
If (Flag) {
DataView dv = ds.Tables[“Emp”].DefaultView;
dv.RowFilter = “Deptno=” + comboBox1.SelectedValue;

dv.Sort = “Salary” or dv.Sort = “Salary Desc”; or dv.Sort = “Salary, Comm”; or dv.Sort = “Salary, Comm Desc”;
}

Note: Just like we can bind a DataTable to DataGridView control in the same way it can also be bound to ComboBox
and ListBox controls using DataSource property, but these controls even if bound with the table they can display
only a single column. So using DisplayMember property of the controls we need to specify which column has to be
displayed. We can also bind another column of the table using ValueMember property of the controls but that
column values will not be visible to end user whereas we can access them in code using SelectedValue property of
control for the selected DisplayMember.
Loading multiple tables into a DataSet from different DataSources using different DataAdapter’s:
Add a new form in the project; place a SplitContainer on it which comes with 2 panels in it. Now place a
button on each panel and set the dock property of button as top. Set the caption of the first button as “Save Data to
Sql Server” and caption of second button as “Save Data to Oracle”. Then add a DataGridView control on each panel
and set their dock property as Fill. Then write the following code:

using System.Configuration; using System.Data.SqlClient; using System.Data.OracleClient;


Declarations:
DataSet ds; SqlDataAdapter sda; SqlCommandBuilder scb;
OracleDataAdapter oda; OracleCommandBuilder ocb;
Under Form Load:
string SConStr = ConfigurationManager.ConnectionStrings["SConStr"].ConnectionString;
string OConStr = ConfigurationManager.ConnectionStrings["OConStr"].ConnectionString;
sda = new SqlDataAdapter("Select Eno, Ename, Job, Salary, Status From Employee Order By Eno", SConStr);
oda = new OracleDataAdapter("Select Grade, LoSal, HiSal From Salgrade Order By Grade", OConStr);
ds = new DataSet(); sda.Fill(ds, "Employee"); oda.Fill(ds, "Salgrade");
dataGridView1.DataSource = ds.Tables["Employee"]; dataGridView2.DataSource = ds.Tables["Salgrade"];
Under Save Data to Sql Server Button:
scb=new SqlCommandBuilder(sda);sda.Update(ds, "Employee");MessageBox.Show("Data saved to Sql Server DB.");
Under Save Data to Oracle Button:
ocb=new OracleCommandBuilder(oda);oda.Update(ds, "Salgrade");MessageBox.Show("Data saved to Oracle DB.");

163
DataRelation:
DataRelation is used to relate two DataTable objects to each other through DataColumn objects. For example,
in a Dept/Emp relationship, “Dept” table is a parent and “Emp” table is a child of the relationship. This is similar to a
primary key/foreign key relationship. Relationships are created between matching columns in the parent and child
tables. That is, the DataType value for both columns must be identical.

To use foreign key constraint we need a parent table that contains master data and a child table that contains
detailed data corresponding to master data. Parent table should contain a Reference Key Column with a Primary Key
or Unique Key Constraints imposed on it, and child table should contain a Foreign Key Column with Foreign Key
Constraint imposed on it which refers into the values of Reference Key Column. If relationships are established
between tables following rules comes into picture:
1. Cannot store a value in the foreign key column of child table, provided the given value is not present in
reference key column of parent table.
2. Cannot delete a row from parent table provided the given reference key value of the record being deleted
has child records in the child table without addressing what to do with the corresponding child records.
3. Cannot update reference key value of the parent table provided the given reference key value being
updated has child records in the child table without addressing what to do with the corresponding child
records.

If we want to establish same type of relations between tables of a DataSet also, we can do it with the help
of DataRelation class.
DataRelation (string relname, DataColumn RKColumn, DataColumn FKColumn)

After creating object of DataRelation it has to be added explicitly to the DataSet under which tables were
present using Relations.Add method of DataSet.
<dataset>.Relations.Add(DataRelation dr)

For deleting or updating reference key values in parent table if the reference key value has an child records
in the child table some rules comes into picture for delete and update known as DeleteRules and UpdateRules, those
are:

1. None: Cannot delete or update reference key value of parent table when corresponding child records exists in
child table, this rule is applied by default under DB's.
2. Cascade: In this case we can delete or update reference key values of parent table, but the corresponding child
records in child table will also be deleted or updated, this rule is applied by default in case of DataSet's.
3. Set Null: In this case also we can delete or update reference key values of parent table but the corresponding child
records foreign key value changes to null.
4. Set Default: This is same as Set Null, but in this case the corresponding child records foreign key value changes
to default value of the column.

Note: we need to apply required rule for delete or update on DataRelation using following statements:
<datarelation>.ChildKeyConstraint.DeleteRule = Rule.<rule>;
<datarelation>.ChildKeyConstraint.UpdateRule = Rule.<rule>;

To use SetDefault rule first we need to set a default value for foreign column using the following statement:
<datatable>.Columns[name].DefaultValue=<value>

164
Loading multiple tables into a DataSet and establishing relation between the tables:
Add a new form in the project, place a SplitContainer on it and change the Orientation property of the
control as Horizontal so that the panels under the SplitContainer will be horizontally aligned (default is vertical).
Place a DataGridView control on each panel and set their Dock property as Fill. Now write the following code:

using System.Configuration; using System.Data.SqlClient;


Declarations:
DataSet ds; DataRelation dr; SqlConnection con; SqlDataAdapter da1, da2;
Under Form Load:
string ConStr = ConfigurationManager.ConnectionStrings[SConStr"].ConnectionString;
con = new SqlConnection(ConStr); ds = new DataSet();
da1 = new SqlDataAdapter(“Select * From Dept”, con); da1.Fill(ds, "Dept");
da2 = new SqlDataAdapter(“Select * From Emp”, con); da2.Fill(ds, "Emp");
dr = new DataRelation("EmpDept", ds.Tables[“Dept”].Columns["Deptno"], ds.Tables[“Emp”].Columns["Deptno"]);
ds.Relations.Add(dr);
dr.ChildKeyConstraint.DeleteRule = Rule.None; dr.ChildKeyConstraint.UpdateRule = Rule.None;
dataGridView1.DataSource = ds.Tables["Dept"]; dataGridView2.DataSource = ds.Tables["Emp"];
Note: Use the following statement if required for setting a default value to foreign key column:
ds.Tables["Emp"].Columns["Deptno"].DefaultValue = 40;
Displaying data in Parent/Child view using DataGrid Control:
It is possible to display the data in Parent/Child view with the help of a control known as DataGrid which is
available before 2.0 version of .NET framework, but doesn’t support data manipulations like DataGridView control.
To test this add a new form in the project, open the toolbox right click on “Data Tab” and select “Choose Items”, in
the window opened select the control “DataGrid” and click ok which adds the control under “Data Tab”. Now place
a DataGrid control on form and write the following code:

using System.Configuration; using System.Data.SqlClient;


Declarations: DataSet ds; SqlDataAdapter da;
Under Form Load:
string ConStr = ConfigurationManager.ConnectionStrings["SConStr"].ConnectionString;
ds = new DataSet(); da=new SqlDataAdapter("Select * From Dept", ConStr); da.Fill(ds, "Dept");
da.SelectCommand.CommandText = "Select * From Emp"; da.Fill(ds, “Emp”);
ds.Relations.Add("MasterDetail", ds.Tables[0].Columns["Deptno"], ds.Tables[1].Columns["Deptno"]);
dataGrid1.DataSource = ds;
Major Differences between DataSet and DataReader:
• DataSet is disconnected whereas DataReader is connected while reading data.
• If we want to cache data and pass to a different tier DataSet’s will be the best choice.
• If we want to move back while reading records, DataReader does not support this functionality.
• DataSet’s will internally store the data in XML format that is the reason why they can hold data loaded from
multiple databases also, but not possible in case of DataReader.
• One of the biggest drawbacks of DataSet is speed as DataSet carry considerable overhead because of
relations, multiple tables, etc.
• Using the DataReader increases application performance and reduces system overheads, this is due to one
row at a time is stored in memory.
• DataReader’s are suitable for Web applications, whereas DataSet’s are suitable for windows applications.

165
Stored Procedures
Whenever we want to interact with a database from an application we use SQL statements. When we use
SQL statements within the application we have a problem i.e. when the application runs SQL Statements will be sent
to Database for execution and there those SQL statements will be parsed (compile) and then executed. The process
of parsing takes place each time we run the application and because of this performance of our application
decreases. To overcome the above problems write SQL Statements directly under Database only with in an object
known as Stored Procedure and then call them for execution. As a SP is a pre-compiled block of code that is ready
for execution, will directly execute the statements without parsing them each time.

Syntax to define a Stored Procedure:


Create Procedure <Name> [(<Parameter List>)]
As
Begin
<Stmts>
End;
• SP’s is similar to a method in our language.
public void Test() //Method in CSharp
Create Procedure Test() //Stored Procedure in Sql Server

• If required we can also define parameters but only optional. If we want to pass parameters to a Sql Server
SP prefix the special character “@” before parameter name.
public void Test(int x) //CSharp
Create Procedure Test(@x int) //Sql Server

• A SP can also return values, to return a value we use out clause in Oracle and Output clause in Sql Server.
public void Test(int x, ref|out int y) //CSharp
Create Procedure Test(@x int, @y int out|output) //Sql Server
Creating a Stored Procedure:
We can create a SP in Sql Server either by using Sql Server Management Studio or Visual Studio.Net also. To
create a SP from Visual Studio first we need to configure our Database under Server Explorer, to do this go to view
menu, select Server Explorer which gets launched on LHS of the studio. To configure it right click on the node “Data
Connections”, select “Add Connection” which opens a window asking to choose a Data Source select “MS Sql Server”,
click ok, which opens “Add Connection” window and under it provide the following details:

1. Server Name: <Name of the Server>


2. Authentication: Windows or Sql Server (provide User Name and Password)
3. Database: CSDB

166
Click on the OK button which adds the DB under Server Explorer, expand it, and right click on the node Stored
Procedures, select “Add New Stored Procedure” which opens a window and write the following code:
Create Procedure Employee_Select
As
Select Eno, Ename, Job, Salary, Photo, Status From Employee Order by Eno;
Now right click on the document window & select “Execute” which will create the procedure on Database Server.
Calling a SP from .Net application:
To call a SP from .Net Application we use Command class and the process of calling will be as following:
1. Create instance of class Command by specifying SP Name as CommandText.

2. Change the CommandType property of Command as StoredProcedure because by default CommandType


property is set as Text which executes Sql Stmt’s and after changing that property Command can call SP’s.
cmd.CommandType = CommandType.StoredProcedure;

3. If the SP has any parameters we need to add those parameters to the Command i.e. if the parameter is
input we need to add input parameters by calling “AddWithValue” method and in-case if the parameter is
output we need to add them by calling “Add” method of Command class.

4. If the procedure is a Query Procedure then call ExecuteReader() method of Command class which executes
the procedure and loads data into DataReader, whereas if we want to load data into DataSet then create
DataAdapter class instance passing Command as a parameter and call Fill Method. If the SP contains any
Non-Query operations then call ExecuteNonQuery method of Command to execute the SP.
Calling above Stored Procedure using DataAdapter: Add a new form in the project, place a DataGridView control
on it, set Dock property as “Fill” and write following code:

using System.Configuration; using System.Data.SqlClient;


Declarations: DataSet ds; DataAdapter da;
Under Form Load:
string ConStr = ConfigurationManager.ConnectionStrings["SConStr"].ConnectionString;
da = new SqlDataAdapter(“Employee_Select”, ConStr);
da.SelectCommand.CommandType = CommandType.StoredProcedure;
ds = new DataSet(); da.Fill(ds, “Employee”);
dataGridView1.DataSource = ds.Tables[0];
Calling the above Stored Procedure using Command: Add a new form and design it as following.

using System.Configuration; using System.Data.SqlClient;


Declarations: SqlConnection con; SqlCommand cmd; SqlDataReader dr;

167
Under Form Load:
string ConStr = ConfigurationManager.ConnectionStrings["SConStr"].ConnectionString;
con = new SqlConnection(ConStr); cmd = new SqlCommand("Employee_Select", con);
cmd.CommandType = CommandType.StoredProcedure; con.Open();
dr = cmd.ExecuteReader(); ShowData();
private void ShowData() {
if (dr.Read()) {
textBox1.Text = dr[0].ToString(); textBox2.Text = dr[1].ToString();
textBox3.Text = dr[2].ToString(); textBox4.Text = dr[3].ToString();
checkBox1.Checked = (bool)dr["Status"];
}
else
MessageBox.Show("Last record of the table");
}
Under Next Button: ShowData();
Parameters of Stored Procedures:
Stored Procedure’s can be defined with parameters either to send values for execution or receiving values after
execution. While calling a Stored Procedure which has parameters from our .Net application, for each parameter of
the Procedure we need to add a matching parameter under Command i.e. for input parameter matching input
parameter has to be added and for output parameter a matching output parameter has to be added. Every
parameter that is added under Command has 5 attributes to it like Name, Value, DbType, Size and Direction which
can be Input (d) or Output.
• Name refers to name of the parameter that is defined in SP.
• Value refers to value being assigned in case of input or value we are expecting in case of output.
• DbType refers to data type of the parameter in terms of the Database where the SP exists.
• Size refers to size of data.
• Direction specifies whether the parameter is Input or Output.

If a SP has Input or Output parameters we need to specify the following attributes while adding the parameters:

Input Output
Name Yes Yes
Value Yes No
DbType Yes [*] Yes
Size No Yes [**]
Direction No Yes

*Required only if the value supplied is null.


**Required only in case of variable length types.

Adding Output parameter under Command:


cmd.Parameters.Add(string pname, DbType type, int size).Direction = ParameterDirection.Output;

After executing the SP we can capture Output parameter values as following:


Object obj = cmd.Parameters[string pname].Value;

168
Performing Select and DML Operations using Stored Procedures: To perform select, insert, update and delete
operations using SP’s first define the following procedures in Database.
Alter PROCEDURE Employee_Select (@Eno Int = Null, @Status Bit = Null)
As
Begin
If @Eno Is Null And @Status Is Null --Retrieves all records
Select Eno, Ename, Job, Salary, Photo, Status From Employee;
Else If @Eno Is Null And @Status Is Not Null --Retrieves all records based on status
Select Eno, Ename, Job, Salary, Photo, Status From Employee Where Status=@Status;
Else If @Eno Is Not Null And @Status Is Not Null --Retrieves single record based on Eno and Status
Select Eno, Ename, Job, Salary, Photo, Status From Employee Where Eno=@Eno And Status=@Status;
End
Create Procedure Employee_Insert(@Ename Varchar(50), @Job Varchar(50), @Salary Money, @Photo Image, @Eno
Int Output)
As
Begin
Begin Transaction
Select @Eno = IsNull(Max(Eno), 1000) + 1 From Employee;
Insert Into Employee (Eno, Ename, Job, Salary, Photo) Values (@Eno, @Ename, @Job, @Salary, @Photo);
Commit Transaction;
End;
Create Procedure Employee_Update(@Eno Int, @Ename Varchar(50), @Job Varchar(50), @Salary Money, @Photo
Image)
As
Update Employee Set Ename=@Ename, Job=@Job, Salary=@Salary, Photo=@Photo Where Eno=@Eno;
CREATE PROCEDURE Employee_Delete(@Eno Int)
As
Update Employee Set Status=0 Where Eno=@Eno;
Add a new form, design it as following by adding an OpenFileDialog control and then write below code:

using System.Configuration; using System.IO; using System.Data.SqlClient; using Microsoft.VisualBasic;


Declarations:
DataSet ds; SqlConnection con; SqlCommand cmd; SqlDataAdapter da; string ImgPath=""; byte[] ImgData = null;
Under Form Load:
string ConStr = ConfigurationManager.ConnectionStrings["SConStr"].ConnectionString;
con = new SqlConnection(ConStr); cmd = new SqlCommand();
cmd.Connection = con; cmd.CommandType = CommandType.StoredProcedure;
Under Clear Button:

169
textBox1.Text = textBox2.Text = textBox3.Text = textBox4.Text = "";
pictureBox1.Image = null; ImgData = null; ImgPath = ""; textBox2.Focus();
Under Select Button:
string value = Interaction.InputBox("Enter an Employee No.");
if (int.TryParse(value, out int Eno)) {
cmd.Parameters.Clear(); cmd.CommandText = "Employee_Select";
cmd.Parameters.AddWithValue("@Eno", Eno); cmd.Parameters.AddWithValue("@Status", true);
da = new SqlDataAdapter(cmd); ds = new DataSet(); da.Fill(ds, "Employee");
if (ds.Tables[0].Rows.Count > 0) {
ImgData = null; ImgPath =""; pictureBox1.Image = null;
textBox1.Text = ds.Tables[0].Rows[0][0].ToString(); textBox2.Text = ds.Tables[0].Rows[0][1].ToString();
textBox3.Text = ds.Tables[0].Rows[0][2].ToString(); textBox4.Text = ds.Tables[0].Rows[0][3].ToString();
if (ds.Tables[0].Rows[0][4] != DBNull.Value) {
ImgData = (byte[])ds.Tables[0].Rows[0][4];
MemoryStream ms = new MemoryStream(ImgData);
pictureBox1.Image = Image.FromStream(ms);
}
else
MessageBox.Show("Employee doesn't exist, please check the given employee number.", "Warning",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
else
MessageBox.Show("Enter an integer value as Employee No.", “Warning”, MessageBoxButtons.OK,
MessageBoxIcon.Warning);
Under Insert Button:
try {
cmd.Parameters.Clear(); cmd.CommandText = "Employee_Insert";
cmd.Parameters.AddWithValue("@Ename", textBox2.Text);
cmd.Parameters.AddWithValue("@Job", textBox3.Text);
cmd.Parameters.AddWithValue("@Salary", textBox4.Text);
if(ImgPath.Trim().Length > 0) {
ImgData = File.ReadAllBytes(ImgPath); cmd.Parameters.AddWithValue("@Photo", ImgData);
}
else {
cmd.Parameters.AddWithValue("@Photo", DBNull.Value);
cmd.Parameters["@Photo"].SqlDbType = SqlDbType.Image;
}
cmd.Parameters.Add("@Eno", SqlDbType.Int).Direction = ParameterDirection.Output;
con.Open(); cmd.ExecuteNonQuery();
textBox1.Text = cmd.Parameters["@Eno"].Value.ToString(); ImgPath = ""; ImgData = null;
}
catch (Exception ex)
{ MessageBox.Show(ex.Message, "Error Message", MessageBoxButtons.OK, MessageBoxIcon.Error); }
finally { con.Close(); }
Under Update Button:
try {

170
cmd.Parameters.Clear(); cmd.CommandText = "Employee_Update";
cmd.Parameters.AddWithValue("@Eno", textBox1.Text);
cmd.Parameters.AddWithValue("@Ename", textBox2.Text);
cmd.Parameters.AddWithValue("@Job", textBox3.Text);
cmd.Parameters.AddWithValue("@Salary", textBox4.Text);
if (ImgPath.Trim().Length == 0 && ImgData == null) {
cmd.Parameters.AddWithValue("@Photo", DBNull.Value);
cmd.Parameters["@Photo"].SqlDbType = SqlDbType.Image;
}
else if (ImgPath.Trim().Length > 0) {
ImgData = File.ReadAllBytes(ImgPath);
cmd.Parameters.AddWithValue("@Photo", ImgData);
}
else { cmd.Parameters.AddWithValue("@Photo", ImgData); }
con.Open(); cmd.ExecuteNonQuery();
MessageBox.Show("Record updated under the database table.", "Information Message", MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
catch (Exception ex)
{ MessageBox.Show(ex.Message, "Error Message", MessageBoxButtons.OK, MessageBoxIcon.Error); }
finally { con.Close();}
Under Delete Button:
try {
cmd.Parameters.Clear(); cmd.CommandText = "Employee_Delete";
cmd.Parameters.AddWithValue("@Eno", textBox1.Text);
con.Open(); cmd.ExecuteNonQuery();
btnClear.PerformClick();
MessageBox.Show("Record deleted under the database table.", "Sql Message", MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
catch (Exception ex)
{ MessageBox.Show(ex.Message, "Error Message", MessageBoxButtons.OK, MessageBoxIcon.Error); }
finally { con.Close(); }
Under Close Button: this.Close();
Under Load Image Button:
openFileDialog1.Filter = "Jpeg Images|*.jpg|Bitmap Images|*.bmp|All Files|*.*";
DialogResult dr = openFileDialog1.ShowDialog();
if (dr == DialogResult.OK) {
ImgPath = openFileDialog1.FileName; pictureBox1.ImageLocation = ImgPath;
}
Under Image Delete Button:
pictureBox1.Image = null; ImgData = null; ImgPath = "";
Accessing All, Active and In-Active records by using Select Stored Procedure:
Create a new form for accessing all, active and in-active records from the table using select SP. To do this
add a new Form in the project, place a ComboBox control on the top center, goto it’s items property and add the

171
values: All, Active & In-Active; now place a DataGridView Control, goto its properties and Set AllowUserToAddRows
and AllowUserToDeleteRows property as false, ReadOnly Property as true and then write the following code:

DataGridView

using System.Configuration; using System.Data.SqlClient;


Declarations: DataSet ds; SqlConnection con; SqlDataAdapter da;
Under Form Load:
string ConStr = ConfigurationManager.ConnectionStrings["SConStr"].ConnectionString;
con = new SqlConnection(ConStr); da = new SqlDataAdapter("Employee_Select", con);
da.SelectCommand.CommandType = CommandType.StoredProcedure; comboBox1.SelectedIndex = 0;
Under ComboBox SelectedIndexChanged:
da.SelectCommand.Parameters.Clear();
if (comboBox1.SelectedIndex == 1) { da.SelectCommand.Parameters.AddWithValue("@Status", true); }
else if(comboBox1.SelectedIndex == 2) { da.SelectCommand.Parameters.AddWithValue("@Status", false); }
ds = new DataSet(); da.Fill(ds, "Employee"); dataGridView1.AutoGenerateColumns = false;
dataGridView1.DataSource = ds.Tables[“Employee”]; GenerateColumns();
private void GenerateColumns () {
dataGridView1.Columns.Clear();
DataGridViewTextBoxColumn EnoColumn = new DataGridViewTextBoxColumn();
EnoColumn.DataPropertyName = "Eno"; EnoColumn.HeaderText = "Eno"; EnoColumn.Width = 65;
EnoColumn.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter;
DataGridViewTextBoxColumn EnameColumn = new DataGridViewTextBoxColumn();
EnameColumn.DataPropertyName = "Ename"; EnameColumn.HeaderText = "Ename"; EnameColumn.Width = 100;
EnameColumn.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter;
DataGridViewTextBoxColumn JobColumn = new DataGridViewTextBoxColumn();
JobColumn.DataPropertyName = "Job"; JobColumn.HeaderText = "Job"; JobColumn.Width = 120;
JobColumn.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter;
DataGridViewTextBoxColumn SalaryColumn = new DataGridViewTextBoxColumn();
SalaryColumn.DataPropertyName = "Salary"; SalaryColumn.HeaderText = "Salary"; SalaryColumn.Width = 130;
SalaryColumn.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter;
SalaryColumn.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
DataGridViewCheckBoxColumn StatusColumn = new DataGridViewCheckBoxColumn();
StatusColumn.DataPropertyName = "Status"; StatusColumn.HeaderText = "Status"; StatusColumn.Width = 75;
StatusColumn.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter;
DataGridViewImageColumn PhotoColumn = new DataGridViewImageColumn();
PhotoColumn.DataPropertyName = "Photo"; PhotoColumn.HeaderText = "Photo"; PhotoColumn.Width = 200;
PhotoColumn.ImageLayout = DataGridViewImageCellLayout.Stretch;
PhotoColumn.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter;
dataGridView1.Columns.Add(EnoColumn); dataGridView1.Columns.Add(EnameColumn);
dataGridView1.Columns.Add(JobColumn); dataGridView1.Columns.Add(SalaryColumn);
dataGridView1.Columns.Add(StatusColumn); dataGridView1.Columns.Add(PhotoColumn);
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)

172
{ dataGridView1.Rows[i].Height = 200; }
}
Note: Create the following tables on your CSDB Database to try the examples show in the document.

Create Table Dept (Deptno Int Constraint Deptno_Pk Primary Key, Dname Varchar(50), Loc Varchar(50))

Insert into Dept values(10, 'Marketing', 'Mumbai')


Insert into Dept values(20, 'Sales', 'Chennai')
Insert into Dept values(30, 'Finance', 'Delhi')
Insert into Dept values(40, 'Production', 'Kolkota')
--------------------------------------------------------------------------------------------------------------------------------------------------------
Create table Emp (Empno Int Constraint Empno_Pk Primary Key, Ename Varchar(100), Job Varchar(100), Mgr Int,
HireDate Date, Salary Money, Comm Money, Deptno Int References Dept(Deptno))

Insert into Emp Values(1001, 'Scott', 'President', NULL, '01/01/88', 5000, NULL, 10)
Insert into Emp Values(1002, 'Clark', 'Manager', 1001, '01/01/88', 4000, NULL, 10)
Insert into Emp Values(1003, 'Smith', 'Manager', 1001, '01/01/90', 3500, 500, 20)
Insert into Emp Values(1004, 'Vijay', 'Manager', 1001, '01/01/92', 4000, NULL, 30)
Insert into Emp Values(1005, 'Ajay', 'Salesman', 1003, '02/04/89', 3000, 300, 20)
Insert into Emp Values(1006, 'John Smith', 'Salesman', 1003, '02/08/88', 3300, 600, 20)
Insert into Emp Values(1007, 'Venkat', 'Salesman', 1003, '04/15/88', 3300, 0, 20)
Insert into Emp Values(1008, 'Vinod', 'Clerk', 1003, '01/15/88', 2400, NULL, 20)
Insert into Emp Values(1009, 'Suneel', 'Clerk', 1004, '05/12/83', 2000, NULL, 30)
Insert into Emp Values(1010, 'Srinivas', 'Analyst', 1004, '03/01/89', 3400, NULL, 30)
Insert into Emp Values(1011, 'Smyth', 'Analyst', 1004, '03/01/89', 3600, NULL, 30)
Insert into Emp Values(1012, 'Madan', 'Analyst', 1004, '01/09/91', 3100, NULL, 30)
Insert into Emp Values(1013, 'JohnSmith', 'Clerk', 1002, '01/06/88', 1800, NULL, 10)
Insert into Emp Values(1014, 'Raju', 'Clerk', 1005, '06/01/89', 2300, NULL, 20)
Insert into Emp Values(1015, 'Ramesh', 'Clerk', 1011, '08/22/90', 2500, NULL, 30)
Insert into Emp Values(1016, 'Aarush', 'Manager', 1001, '07/15/90', 4200, NULL, 40)
Insert into Emp Values(1017, 'Sridhar', 'Clerk', 1016, '07/20/90', 2500, NULL, 40)
Insert into Emp Values(1018, 'Rahul', 'Supervisor', 1016, '08/01/90', 3500, NULL, 40)
Insert into Emp Values(1019, 'Krishna', 'Fabricator', 1018, '08/12/90', 3100, NULL, 40)
Insert into Emp Values(1020, 'Aaron', 'Fabricator', 1018, '08/21/90', 2900, NULL, 40)
Insert into Emp Values(1021, 'Dave', 'Analyst', 1004, '08/22/90', 3500, NULL, 30)
Insert into Emp Values(1022, 'Kristane', 'Administrator', 1002, '08/22/90', 3000, NULL, 10)
Insert into Emp Values(1023, 'Sophia', 'Administrator', 1003, '08/22/90', 3000, NULL, 20)
Insert into Emp Values(1024, 'Racheal', 'Administrator', 1004, '08/22/90', 3000, NULL, 30)
Insert into Emp Values(1025, 'Elizabeth', 'Administrator', 1016, '08/22/90', 3000, NULL, 40)
--------------------------------------------------------------------------------------------------------------------------------------------------------
Create Table SalGrade(Grade Int, LoSal Money, Hisal Money)

Insert into SalGrade Values(1, 1300, 1800)


Insert into SalGrade values(2, 1801, 2700)
Insert into SalGrade values(3, 2701, 3500)
Insert into SalGrade values(4, 3501, 5000)

173
Insert into SalGrade values(5, 5001, 8000)
Insert into SalGrade values(6, 8001, 10000)
Collections
Arrays are simple data structures used to store data items of a specific type. Although commonly used,
arrays have limited capabilities. For instance, you must specify an array’s size, and if at execution time, you wish to
modify it, you must do so manually by creating a new array or by using Array class’s Resize method, which creates a
new array and copies the existing elements into the new array.
Collections are a set of pre-packaged data structures that offer greater capabilities than traditional arrays.
They are reusable, reliable, powerful and efficient and have been carefully designed and tested to ensure quality
and performance. Collections are similar to arrays but provide additional functionalities, such as dynamic resizing -
they automatically increase their size at execution time to accommodate additional elements, inserting of new
elements and removing of existing elements.
Initially .NET introduced so many collection classes under the namespace System.Collections like Stack,
Queue, LinkedList, SortedList, ArrayList, Hashtable etc and you can work out with these classes in your application
where you need the appropriate behaviour.
To use these classes open a new project of type “Console Application” naming it as “CollectionsProject”,
now under the first class Program.cs write the following code to use the Stack class which works on the principle
First In Last Out (FILO) or Last In First Out (LIFO):
using System.Collections;
class Program {
static void Main(string[] args) {
Stack s = new Stack(); s.Push(10); s.Push("Hello");
s.Push(DateTime.Now.ToShortDateString()); s.Push(true); s.Push(67.8); s.Push('A');
foreach (object obj in s) { Console.Write(obj + " "); } Console.WriteLine();
Console.WriteLine(s.Pop());
foreach (object obj in s) { Console.Write(obj + " "); } Console.WriteLine();
Console.WriteLine(s.Peek());
foreach (object obj in s) { Console.Write(obj + " "); } Console.WriteLine();
Console.WriteLine(s.Count); s.Clear(); Console.WriteLine(s.Count);
Console.ReadLine();
}
}
Using Queue class which works on the principle First In First Out (FIFO):
using System.Collections;
class Class1 {
static void Main() {
Queue q = new Queue(); q.Enqueue(50); q.Enqueue("World"); q.Enqueue(false);
q.Enqueue('A'); q.Enqueue(DateTime.Now.ToShortDateString()); q.Enqueue(45.73);
foreach (object obj in q) { Console.Write(obj + " "); } Console.WriteLine();
Console.WriteLine(q.Dequeue());
foreach (object obj in q) { Console.Write(obj + " "); } Console.ReadLine();
}
}

174
Auto-Resizing of Collections: The capacity of a collection increases dynamically i.e. when we add new elements to a
Collection the size keeps on incrementing automatically. Every collection class has 3 constructors to it and the
behaviour of collections will be as following when created instance using different constructor:
i. Default Constructor: initializes a new instance of the collection class that is empty and has the default
initial capacity as zero which becomes 4 after adding the first element and from then when ever needed
the current capacity doubles.
ii. Collection(int Capacity): Initializes a new instance of the collection class that is empty and has the
specified initial capacity, here also when requirement comes current capacity doubles.
iii. Collection(Collection c): Initializes a new instance of the collection class that contains elements copied
from the specified collection and that has the same initial capacity as the number of elements copied,
here also when requirement comes current capacity doubles.
ArrayList: this collection class works same as an array but provides auto resizing, inserting and deleting of items.
using System.Collections;
class Class2 {
static void Main() {
ArrayList Coll1 = new ArrayList(2); Console.WriteLine("Initial capacity of collection: " + Coll1.Capacity);
Coll1.Add(10); Console.WriteLine("Capacity after adding 1st item: " + Coll1.Capacity);
Coll1.Add(true); Coll1.Add(DateTime.Now.ToShortDateString()); Coll1.Add(true);
Console.WriteLine("Capacity after adding 4th item: " + Coll1.Capacity);
Coll1.Add(45.7); Console.WriteLine("Capacity after adding 5th item: " + Coll1.Capacity); Coll1.Add("Hello");
for (int i = 0; i < Coll1.Count; i++) { Console.Write(Coll1[i] + " "); } Console.WriteLine();
//Coll1.Remove(true); or //Coll1.RemoveAt(1); or Coll1.RemoveRange(1, 1); //Removes an item from ArrayList
foreach (object obj in Coll1) { Console.Write(obj + " "); } Console.WriteLine();
Coll1.Insert(1, 'Z'); foreach (object obj in Coll1) { Console.Write(obj + " "); } Console.WriteLine("\n");

ArrayList Coll2 = new ArrayList(Coll1);


foreach (object obj in Coll2) { Console.Write(obj + " "); } Console.WriteLine();
Console.WriteLine("Initial capacity of new collection: " + Coll2.Capacity);
Coll2.Add(3.14f); Console.WriteLine("New capacity of new collection: " + Coll2.Capacity);
Coll2.TrimToSize(); Console.WriteLine("Capacity of new collection after calling Trim: " + Coll2.Capacity);
Console.ReadLine();
}
}
Hashtable: it is a collection with stores elements in it as “Key/Value Pairs” i.e. Array and ArrayList also has a key to
access the values under them which is the index that starts at 0 to number of elements - 1, where as in case of
Hashtable these keys can also be defined by us and can be of any data type.

using System.Collections;
class Class3 {
static void Main() {
Hashtable Emp = new Hashtable();
Emp.Add("EmpId", 1005); Emp.Add("Name", "John"); Emp.Add("Job", "Manager");
Emp.Add("HireDate", DateTime.Parse("01/21/2018"));
Emp.Add("MgrId", 1001); Emp.Add("Salary", 25000.00); Emp.Add("Status", true);
Emp.Add("Mobile", "98327 12742"); Emp.Add("Email", "[email protected]");
Emp.Add("DeptId", 30); Emp.Add("Dname", "Sales"); Emp.Add("Location", "Mumbai");

175
foreach(object key in Emp.Keys) { Console.WriteLine(key + ": " + Emp[key]); } Console.ReadLine();
}
}
Generics: Generics are added in CSharp version 2.0 introducing to the .NET Framework the concept of type
parameters, which make it possible to design classes, and methods that defer the specification of one or more types
until the class or method is declared and instantiated by client code. For example, by using a generic type parameter
“T” you can write a single class that other client code can use without incurring the cost or risk of runtime casts or
boxing operations, in simple words Generics allow you to define a class with placeholders for the type of its fields,
methods, parameters, etc. Generics replace these placeholders with some specific type at consumption time. To
understand these add a class naming it as GenericMethods.cs and write the following code:
class GenericMethods {
public bool AreEqual<T>(T a, T b) {
if(a.Equals(b)) { return true; }
else { return false; }
}
static void Main() {
GenericMethods obj = new GenericMethods();
bool b1 = obj.AreEqual<int>(10, 20); bool b2 = obj.AreEqual<string>("Nit", "Nit");
bool b3 = obj.AreEqual<double>(12.34, 56.678); bool b4 = obj.AreEqual<char>(‘A’, ‘A’);
Console.WriteLine(b1); Console.WriteLine(b2); Console.WriteLine(b3); Console.WriteLine(b4); Console.ReadLine();
}
}
Just like we are passing Type parameter to methods it is possible to pass them to a class also, to test this
add a code file naming it as TestGenericClass.cs and write the following:
using System;
namespace CollectionsProject {
class Math<T> {
public void Add(T x, T y) {
dynamic a = x; dynamic b = y; Console.WriteLine(a + b);
}
public void Sub(T x, T y) {
dynamic a = x; dynamic b = y; Console.WriteLine(a - b);
}
public void Mul(T x, T y) {
dynamic a = x; dynamic b = y; Console.WriteLine(a * b);
}
public void Div(T x, T y) {
dynamic a = x; dynamic b = y; Console.WriteLine(a / b);
}
}
class TestGenericClass {
static void Main() {
Math<int> pi = new Math<int>();
pi.Add(100, 200); pi.Sub(234, 123); pi.Mul(12, 46); pi.Div(900, 45);
Math<double> pd = new Math<double>();
pd.Add(145.35, 12.5); pd.Sub(45.6, 23.4); pd.Mul(15.67, 3.4); pd.Div(168.2, 14.5); Console.ReadLine();

176
}
}
}
Generic Collections: these are also introduced in C# 2.0 which are extension to collections we have been discussing
above, in case of collection classes the elements being added in them are of type object, so we can store any type
of values in them which requires boxing and un-boxing, where as in case of generic collections we can store specified
type of values which provides type safety. Microsoft has re-implemented all the existing collection classes under a
new namespace System.Collections.Generic but the main difference is while creating object of generic collection
classes we need to explicitly specify the type of values we want to store under them. In this namespace we have
been provided with many classes like classes in System.Collections namespace as following:
Stack<T>, Queue<T>, LinkedList<T>, SortedList<T>, List<T>, Dictionary<TKey, TValue>
Note: <T> referes to the type of values we want to store under them. For example:

Stack<int> si = new Stack<int>(); //Stores integer values only


Stack<float> sf = new Stack<float>(); //Stores float values only
Stack<string> ss = new Stack<string>(); //Stores string values only
List: this class is same as ArrayList we have discussed under collections above.

class Class4 {
static void Main() {
List<int> Coll = new List<int>();
Coll.Add(10); Coll.Add(20); Coll.Add(30); Coll.Add(40); Coll.Add(50); Coll.Add(60); Coll.Add(70); Coll.Add(80);
for (int i = 0; i < Coll.Count; i++) { Console.Write(Coll[i] + " "); } Console.WriteLine();
Coll.Insert(4, 45); foreach (int i in Coll) { Console.Write(i + " "); } Console.WriteLine();
Coll.RemoveAt(6); foreach (int i in Coll) { Console.Write(i + " "); } Console.WriteLine(); Console.ReadLine();
}
}
Dictionary: this class is same as Hashtable we have discussed under collections but here while creating the object
we need to specify the type for keys as well as for values also, as following:
Dictionary<TKey, TValue>
class Class5 {
static void Main() {
Dictionary<string, object> dtEmp = new Dictionary<string, object>();
Emp.Add("EmpId", 1005); Emp.Add("Name", "John"); Emp.Add("Job", "Manager");
Emp.Add("HireDate", DateTime.Parse("01/21/2018"));
Emp.Add("MgrId", 1001); Emp.Add("Salary", 25000.00); Emp.Add("Status", true);
Emp.Add("Mobile", "98327 12742"); Emp.Add("Email", "[email protected]");
Emp.Add("DeptId", 30); Emp.Add("Dname", "Sales"); Emp.Add("Location", "Mumbai");
foreach (string key in Emp.Keys) { Console.WriteLine(key + ": " + Emp[key]); } Console.ReadLine();
}
}
Note: The type of values being stored in a generic collection can be of user-defined type values also like a class type
or structure type that is defined to represent an entity as following:

177
List<Customer> Customers = new List<Customer>(); //Assume Customer is a user-defined class type that
represents an entity Customer, so we can store objects of Customer type under the List where each object can
internally represent different attributes of Customer like Id, Name, City, Balance, Status etc. To Test this add a Code
File Class6.cs and write the following code in it:
using System; using System.Collections.Generic;
namespace CollectionsProject {
public class Customer {
public int Id { get; set; }
public string Name { get; set; }
public string City { get; set; }
public double Balance { get; set; }
public bool Status { get; set; }
public override string ToString() => Id + " " + Name + " " + City + " " + Balance + " " + Status;
}
class Class6 {
static void Main() {
Customer c1 = new Customer { Id = 101, Name = "Scott", City = "Delhi", Balance = 15000.00, Status = true };
Customer c2 = new Customer { Id = 102, Name = "Dave", City = "Mumbai", Balance = 10000.00, Status = true };
Customer c3 = new Customer { Id = 103, Name = "Bob", City = "Chennai", Balance = 15000.00, Status = true };
Customer c4 = new Customer { Id = 104, Name = "David", City = "Delhi", Balance = 11000.00, Status = true };
Customer c5 = new Customer { Id = 105, Name = "John", City = "Kolkata", Balance = 4000.00, Status = true };
Customer c6 = new Customer { Id = 106, Name = "James", City = "Agra", Balance = 9000.00, Status = true };
Customer c7 = new Customer { Id = 107, Name = "Jane", City = "Mumbai", Balance = 11000.00, Status = true };
Customer c8 = new Customer { Id = 108, Name = "Steve", City = "Pune", Balance = 4000.00, Status = true };
Customer c9 = new Customer { Id = 109, Name = "Suresh", City = "Bhopal", Balance = 6000.00, Status = true };
Customer c10 = new Customer { Id = 110, Name = "Rehman", City = "Delhi", Balance = 9500.00, Status = true };
List<Customer> Customers = new List<Customer>() { c1, c2, c3, c4, c5, c6, c7, c8, c9, c10 };
foreach (Customer C in Customers) { Console.WriteLine(C); } Console.ReadLine();
}
}
}

Collection Initializers: this is a new feature added in C# 3.0 which allows to initialize a collection directly at the time
of declaration like an array, as following: List<int> li = new List<int>() { 10, 20, 30, 40, 50 };
Add a new class in the project naming it as Class7.cs and write the below code in it:
class Class7 {
static void Main() { //Copying values > 40 from 1 list to another list and arranging them in descending order
List<int> coll1 = new List<int>() { 13,56,29,98,24,54,79,39,8,42,22,93,6,73,35,67,48,18,61,32,86,15,21,81,2 };
List<int> coll2 = new List<int>();
foreach (int i in coll1) { if (i > 40) { coll2.Add(i); } } //Retrieving values of list > 40
coll2.Sort(); //Sorting the new list values in ascending order
coll2.Reverse(); //Reversing new list values to arrange in descending order
Console.WriteLine(String.Join(" ", coll2));
Console.ReadLine();
}
}

178
The above program if used an array, code will be as following (Add a new class Class8.cs and write the below):
class Class8 {
static void Main() {
int[] arr = { 13, 56, 29, 98, 24, 54, 79, 39, 8, 42, 22, 93, 6, 73, 35, 67, 48, 18, 61, 32, 86, 15, 21, 81, 2 };
int Count = 0, Index = 0;
foreach(int i in arr) { if (i > 40) Count += 1; }
int[] brr = new int[Count];
for(int i=0;i<arr.Length;i++) {
if (arr[i] > 40) {
brr[Index] = arr[i]; Index += 1;
}
}
Array.Sort(brr); Array.Reverse(brr);
Console.WriteLine(String.Join(" ", brr)); Console.ReadLine();
}
}
In the above programs we are filtering the values of a List and Array which are greater than 40 and then
arranging them in descending order; to do this we have written a substantial amount of code which is the traditional
process of performing filters on Arrays and Collections.

In C# 3.0 Microsoft has introduced a new language known as “LINQ” much like SQL (which we use
universally with relational databases to perform queries). LINQ allows you to write query expressions (similar to SQL
Queries) that can retrieve information from a wide variety of data sources like objects, databases and xml.
Introduction to LINQ: LINQ stands for Language Integrated Query. LINQ is a data querying methodology which
provides querying capabilities to .NET languages with syntax similar to a SQL Query. LINQ has a great power of
querying on any source of data, where the data source could be collections of objects, database or XML files.

LINQ to Objects: used to perform queries against the in-memory data like an array or collection.

LINQ to Databases:
• LINQ to DataSets is used to perform queries against ADO.NET Data Table’s.
• LINQ to SQL is used to perform queries against the relation database, but only Microsoft SQL Server.
• LINQ to Entities is used to perform queries against any relation database like SQL Server, Oracle, etc.

LINQ to XML (XLinq): used to perform queries against the XML source.
Advantages of LINQ:

179
i. LINQ offers an object-based, language-integrated way to query over data, no matter where that data
came from. So through LINQ we can query database, XML as well as collections.
ii. Compile time syntax checking.
iii. It allows you to query collections, arrays, and classes etc. in the native language of your application like
VB or CSharp.
LINQ to Objects
This is designed to write queries against the in-memory data like an array or collection and filter or sort the
information present under them. Syntax of the query we want to use on objects will be as following:
from <alias> in <array_name | collection_name> [<clauses>] select <alias>
• A Linq Query starts with from and ends with select.
• While using clauses we need to use the alias name we have specified under them, just like we use column
names in case of SQL.
• Clauses can be like where, group by and orderby.
• To use LINQ in your application first we need to import System.Linq namespace.

We can write our previous 2 programs where we have filtered the data of a List or Array and arranged in
sorting order as following using LINQ (Add a new class Class9.cs and write the below):
class Class9 {
static void Main() {
List<int> coll1 = new List<int>() { 13,56,29,98,24,54,79,39,8,42,22,93,6,73,35,67,48,18,61,32,86,15,21,81,2 };
var coll2 = from i in coll1 where i > 40 orderby i descending select i; //Retrieves all elements greater than 40
Console.WriteLine(String.Join(" ", coll2));
int[] arr = { 13, 56, 29, 98, 24, 54, 79, 39, 8, 42, 22, 93, 6, 73, 35, 67, 48, 18, 61, 32, 86, 15, 21, 81, 2 };
var brr = from i in arr where i > 40 orderby i descending select i;
Console.WriteLine(String.Join(" ", brr)); Console.ReadLine();
}
}
Note: the values that are returned by a LINQ query can be captured by using implicitly typed local variables, so in
the above case “coll2” & “brr” are implicitly declared collection/array that stores the values retrieved by the query.
In traditional process of filtering data of an array or collection we have repetition statements that filter
arrays focusing on the process of getting the results i.e. iterating through the elements and checking whether they
satisfy the desired criteria, whereas LINQ specifies, not the steps necessary to get the results, but rather the
conditions that selected elements must satisfy and this is known as declarative programming - as opposed to
imperative programming (which we’ve been using so far) in which we specify the actual steps to perform a task.
Procedural & Object Oriented Languages are a subset of imperative. The queries we have used above specifies that
the result should consist of all the int’s in the List that are greater than 40, but it does not specify how to obtain the
result, C# compiler generates all the necessary code automatically, which is one of the great strengths of LINQ.

LINQ Providers: The syntax of LINQ is built into the language, but LINQ queries may be used in many different
contexts because of libraries known as providers. A LINQ provider is a set of classes that implement LINQ operations
and enable programs to interact with data sources to perform tasks such as sorting, grouping and filtering elements.
When we import the “System.Linq” namespace it contains the LINQ to Objects provider, without importing it the
compiler cannot locate a provider for the LINQ queries and issues errors on LINQ queries.
class Class10 {
static void Main() {

180
string[] colors = { "Red", "Blue", "Green", "Black", "White", "Brown", "Orange", "Purple", "Yellow", "Aqua" };
//var coll = from s in colors select s; //Gets the list of all colors as is
//var coll = from s in colors orderby s select s; //Gets the list of all colors in ascending order
//var coll = from s in colors orderby s descending select s; //Gets the list of all colors in descending order
//var coll = from s in colors where s.Length == 5 select s; //Gets the list of colors whose length is 5 characters

//Getting the list of colors whose name starts with character "B":
//var coll = from s in colors where s[0] == 'B' select s;
//var coll = from s in colors where s.StartsWith("B") select s;
//var coll = from s in colors where s.Substring(0, 1) == "B" select s;
//var coll = from s in colors where s.IndexOf("B") == 0 select s;

//Getting the list of colors whose name ends with character "e":
//var coll = from s in colors where s.EndsWith("e") select s;
//var coll = from s in colors where s[s.Length - 1] == 'e' select s;
//var coll = from s in colors where s.Substring(s.Length - 1) == "e" select s;
//var coll = from s in colors where s.LastIndexOf("e") == s.Length - 1 select s;

//Getting the list of colors whose name contains character "a" at 3rd place:
//var coll = from s in colors where s[2] == 'a' select s;
//var coll = from s in colors where s.IndexOf("a") == 2 select s;
//var coll = from s in colors where s.Substring(2, 1) == "a" select s;

//Getting the list of colors whose name contains character "o" in it:
//var coll = from s in colors where s.Contains('o') || s.Contains('O') select s;
//var coll = from s in colors where s.IndexOf('o') >= 0 || s.IndexOf('O') >= 0 select s;
//var coll = from s in colors where s.ToLower().Contains('o') select s;
//var coll = from s in colors where s.ToUpper().IndexOf('O') >= 0 select s;

//Getting the list of colors whose name dosn't contains character "o" in it:
//var coll = from s in colors where s.IndexOf('o') == -1 && s.IndexOf('O') == -1 select s;
//var coll = from s in colors where s.Contains('o') == false && s.Contains('O') == false select s;
//var coll = from s in colors where s.ToUpper().Contains('O') == false select s;
var coll = from s in colors where s.ToLower().IndexOf('o') == -1 select s;
Console.WriteLine(String.Join(" ", coll)); Console.ReadLine();
}
}
LINQ to SQL
Probably the biggest and most exciting addition to the .Net Framework 3.5 is the addition of the .Net
Language Integrated Query Framework (LINQ) into C# 3.0. Basically, what LINQ provides is a lightweight façade over
programmatic data integration. This is such a big deal because data is King. Pretty much every application deals with
data in some manner, whether that data comes from memory, databases, XML files, text files, or something else.
In C#, programming with objects means a wonderful strongly typed ability to work with code. You can
navigate very easily through the namespaces; work with a debugger in the Visual Studio IDE, and more. However,
when you have to access data, you will notice that things are dramatically different. You end up in a world that is

181
not strongly typed, where debugging is a pain or even non-existent, and you end up spending most of the time
sending strings to the database as commands and as a developer, you also have to be aware of the underlying data
and how it is. Many developers find it very difficult to move from the strongly typed object-oriented world of C# to
the data tier where objects are second-class citizens.
Microsoft has provided LINQ as a lightweight façade that provides a strongly typed interface to the
underlying data stores. LINQ provides the means for developers to stay within the coding environment they are used
to and access the underlying data as objects that work with the IDE, Intellisense, and even debugging. With LINQ,
the queries that you create now become first-class citizens within the .NET Framework alongside everything else you
are used to. When you work with queries for the data store you are working with, you will quickly realize that they
now work and behave as if they are types in the system. This means that you can now use any .NET-compliant
language and query the underlying data stores as you never have before.
LINQ to SQL and Visual Studio:
LINQ to SQL in particular is a means to have a strongly typed interface against a SQL Server database. You
will find the approach that LINQ to SQL provides is by far the easiest approach for querying SQL Server available at
the moment. It is important to remember that LINQ to SQL is not only about querying data, but you can also perform
Insert/Update/Delete operations that you need to perform which are known as CRUD operations
(Create/Read/Update/Delete). Visual Studio comes into strong play with LINQ to SQL in that you will find an
extensive user interface that allows you to design the LINQ to SQL classes you will work with.

To start using LINQ to SQL first open a new Windows Project naming it as “LinqDBProject”, then open the
Server Explorer and create a new table under our database naming the table as “Customer” with the following
columns and also store some initial data in it:
Custid (Int) [PK] Name (Varchar(50)) City (Varchar(50)) Balance (Money) Status (Bit) Not Null Default 1
Adding a LINQ to SQL Class:
To work with LINQ first you need to convert relational objects of DB into object oriented types under the
language and the process of this conversion is known as ORM (Object Relational Mapping) and to perform this we
are provided with a tool under visual studio i.e. OR Designer (Object Relational Designer) which does an outstanding
job of making it as easy as possible.

To start this task, open the “Add New Item” dialog window and in the items of dialog box, you will find
“LINQ to SQL Classes” as an option, name the item as “CSDB.dbml” (Database Markup Language). We can give any
name to the .dbml file but it is always suggested to use our Database name as a name to this, because our database
name is “CSDB” we have named it as “CSDB.dbml”, now click “Add” button which will do the following:

1. Adds a reference to System.Data.Linq assembly which is required to work with “LINQ to Sql”.
2. Under Solution Explorer we will find “CSDB.dbml” and under it we will find 2 sub-items “CSDB.dbml.layout”
and “CSDB.Designer.cs” and under this file only OR-Designer writes all the ORM code converting Relational
Objects into Object Oriented Types.
3. The O/R Designer is added in the studio which will appear as a tab within the document window directly in
the IDE and this is made up of two parts. The first part on the left is for Data Classes, which map to Tables,
Views, etc, dragging such items on this surface will give us a visual representation of those objects. The
second part on the right is for Methods, which map to the Stored Procedures within the DB.

Let us have a look into the code added in CSDB.designer.cs file where we will find a class CSDBDataContent
inheriting from DataContext class; we can view this as something that maps to a Connection type object binding with
the DB. This object works with the connection string and connects to the database for any required operations when

182
we create instance of the class. DataContext class also provides methods like CreateDatabase, DeleteDatabase,
GetTable, ExecuteCommand, ExecuteQuery, SubmitChanges etc, using which we can perform action directly on the
database. Currently this class contains 4 parameterized constructors for creating instance of the class.
Creating the Customer Entity:
For this example, we want to work with the Customer (Entity) table from the CSDB database, which means
that you are going to create a Customer (Entity) class that will use LINQ to SQL map to Customer table. To
accomplishing this task simply open the “Server Explorer” within Visual Studio, configure your DB i.e. CSDB under it,
now drag and drop the Customer table onto the design surface of the O/R Designer in LHS which will prompt with a
window asking for storing of “Connection String” under Config File, so select Yes in it which will add the connection
string into it and also a bunch of code is added to the CSDB.designer.cs file on our behalf with a set of classes in it,
and those classes will give you a strongly typed access to the Customer (Entity) table. When we drag and drop a table
on OR Designer the following actions gets performed internally:

1. Defines a class representing the table (Entity) we have dragged and dropped on the OR Designer where the
name of the class will be same as the table name, as we dropped the Customer table on OR Designer
Customer class gets defined.
2. Defines properties under the class defined representing the table (Entity), where each property represents
each column of the table.
3. Defines a property under the CSDBDataContext class for referring to the table we are working with and the
type of the property will be Table<Entity>, for example, because we are working with Customer Entity the
property name will be Customers and the type of the property will be Table<Customer>.

Apart from the above 3 when we place the first object on the OR Designer it will also perform these activities also:

1. Writes the Connection String in the Web.config file targeting to the database we are working with.
2. Defines a new parameter less constructor under the ASPDBDataContext class and we can use this for
creating the instance for connecting to DB and it only will read the connection string from Web.config.

Note: Table<Entity> is a generic class under System.Data.Linq namespace which contains a set of methods
DeleteOnSubmit, InsertOnSubmit, SingleOrDefault etc. for performing the CRUD operations.
Now place a DataGridView control on the first Form of project, change the name of DataGridView as dgView
and write the following code.

using System.Data.Linq;
Under Form Load:
CSDBDataContext dc = new CSDBDataContext();
Table<Customer> tab = dc.GetTable<Customer>(); or Table<Customer> tab = dc.Customers;
dgView.DataSource = tab;

Note: In the above case, the CSDBDataContext object is used to connect with CSDB database and then the
GetTable<TEntity>() method or Customers property is called to populate the table of type Customer.

183
Now add a new form in project and design it as following:
Declarations: List<Customer> Cust; int Index = 0;
Under Form Load:
CSDBDataContext dc = new CSDBDataContext(); Cust = dc.Customers.ToList(); ShowData();
private void ShowData() {
textBox1.Text = Cust[Index].Custid.ToString(); textBox2.Text = Cust[Index].Name; textBox3.Text = Cust[Index].City;
textBox4.Text = Cust[Index].Balance.ToString(); checkBox1.Checked = Cust[Index].Status;
}
Under Prev Button:
if (Index > 0) {
Index -= 1; ShowData();
}
else {
MessageBox.Show("You are at first record of the table", "Information", MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
Under Next Button:
if (Index < Cust.Count - 1) {
Index += 1; ShowData();
}
else {
MessageBox.Show("You are at last record of the table", "Information", MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
Under Close Button: this.Close();
Performing CRUD operations using LINQ:
Create 2 new Forms as following, change the name of DataGridView on 1st form as dgView and also make
it non-editable. In 2nd form change the modifier of 4 TextBox’s, CheckBox and Clear Button as Internal.

184
Code under First Form
Declarations: CSDBDataContext dc;
private void LoadData() {
dc = new CSDBDataContext(); dgView.DataSource = dc.Customers;
}
Under Form Load: LoadData();
Under Insert Button:
Form4 f = new Form4(); f.ShowDialog(); LoadData();
Under Update Button:
if (dgView.SelectedRows.Count > 0) {
Form4 f = new Form4();
f.textBox1.Text = dgView.SelectedRows[0].Cells[0].Value.ToString();
f.textBox2.Text = dgView.SelectedRows[0].Cells[1].Value.ToString();
f.textBox3.Text = dgView.SelectedRows[0].Cells[2].Value.ToString();
f.textBox4.Text = dgView.SelectedRows[0].Cells[3].Value.ToString();
f.checkBox1.Checked = (bool)dgView.SelectedRows[0].Cells[4].Value;
f.textBox1.ReadOnly = true; f.btnClear.Enabled = false; f.ShowDialog(); LoadData();
}
else {
MessageBox.Show("Select a record for updating", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
Under Delete Button:
if (dgView.SelectedRows.Count > 0) {
if (MessageBox.Show("Do you wish to delete the record?", "Confirmation", MessageBoxButtons.YesNo,
MessageBoxIcon.Question) == DialogResult.Yes) {
int Custid = Convert.ToInt32(dgView.SelectedRows[0].Cells[0].Value);
Customer obj = dc.Customers.SingleOrDefault(C => C.Custid == Custid);
dc.Customers.DeleteOnSubmit(obj); dc.SubmitChanges(); LoadData();
}
}
else{
MessageBox.Show("Select a record for deleting", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
Code under Second Form
Under Save Button:
CSDBDataContext dc = new CSDBDataContext();
if (textBox1.ReadOnly == false) {
Customer obj = new Customer {
Custid = int.Parse(textBox1.Text),
Name = textBox2.Text,
City = textBox3.Text,
Balance = decimal.Parse(textBox4.Text),
Status = checkBox1.Checked
};
dc.Customers.InsertOnSubmit(obj); dc.SubmitChanges();

185
MessageBox.Show("Record added to database table", "Information", MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
else {
Customer obj = dc.Customers.FirstOrDefault(C => C.Custid == int.Parse(textBox1.Text));
obj.Name = textBox2.Text;
obj.City = textBox3.Text;
obj.Balance = decimal.Parse(textBox4.Text);
obj. Status = checkBox1.Checked;
dc.SubmitChanges();
MessageBox.Show("Record modified under database table", "Information", MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
Under Clear Button:
textBox1.Text = textBox2.text = textBox3.Text = textBox4.Text = “”;
checkBox1.Checked = false; textBox1.Focus();
Under Close Button: this.Close();
Performing CRUD (Create (Insert), Read (Select), Update and Delete) Opertions:
To Perform CRUD operations on Sql Server Database by using Linq to Sql we need to adopt the following
process for Insert, Update and Delete:

Steps for Inserting:


1. Create an instance of Customer Entity (Class), which is defined representing the Customer Entity (Table) because
each instance is a record, and then assign values to the properties because those properties represents columns.
2. Call InsertOnSubmit method on the table (Customers) which adds the record into the table in a pending state.
3. Call SubmitChanges method on DataContext object for saving the changes to DB Server.

Steps for Updating:


1. Create reference of the Customer Entity that has to be updated by calling First or FirstOrDefault or SingleOrDefault
or Single method on the table (Customers).
2. Re-assign values to properties of the reference so that old values gets changed to new values.
3. Call SubmitChanges method on DataContext object for saving the changes to DB server.

Steps for Deleting:


1. Create a reference of the Customer Entity that has to be deleted by calling First or FirstOrDefault or
SingleOrDefault or Single method on the table (Customers).
2. Call DeleteOnSubmit method on the table (Customers) that deletes the record from table in a pending state.
3. Call SubmitChanges method on DataContext object for saving the changes to DB server.
Calling Stored Procedures thru LINQ:
If we want to call any SP of Sql Server DB using LINQ we need to first drag and drop the SP on RHS panel of
OR-designer, so that it gets converted into a method under DataContext class with same name of the SP. If the SP
has any parameters those parameters will be defined for the method also, where input parameters of procedure
becomes input parameters and output parameters of procedure becomes ref parameters of the method. For
example if the below SP was dropped on RHS panel of OR-designer:
Create Procedure Add(@x int, @y int, @z int output)

186
The method gets created as following:
public int Add(int? x, int? y, ref int? z)
If the SP contains any non-query operations in it, in such cases the return type of method will be int, where
as if the SP has any select statements in it that returns table results then the return type of the method will be
ISingleResult<T>, where T represents a class that is newly defined when we drag and drop the select SP whose name
will be SP Name suffixed with “Result” i.e. for example if the procedure name is “Employee_Select” then the class
name will be “Employee_SelectResult”. We can find those methods and classes under designer.cs file.
Calling Employee_Select Procedure:
Drag and drop Employee_Select SP on the RHS panel of OR-Designer, take a new form place a ComboBox
control on top center and add values (All, Active and In-Active) using it’s Items property, place a DataGridView
control below the ComboBox, change the name as dgView and write the below code:

Declarations: CSDBDataContext dc;


Under Form Load:
dc = new CSDBDataContext(); comboBox1.SelectedIndex = 0;
Under ComboBox SelectedIndexChanged:
if (comboBox1.SelectedIndex == 0)
dataGridView1.DataSource = dc.Employee_Select(null, null);
else if (comboBox1.SelectedIndex == 1)
dataGridView1.DataSource = dc.Employee_Select(null, true);
else if (comboBox1.SelectedIndex == 2)
dataGridView1.DataSource = dc.Employee_Select(null, false);
Performing CRUD Operations by using Stored Procedures:
Now drag and drop Employee_Insert, Employee_Update, Employee_Delete procedures on the OR-Designer
which we have created earlier. Add a new Form, design it as following, place an OpenFileDialog control on the form
and write the following code:

using System.IO; using System.Data.Linq; using static Microsoft.VisualBasic.Interaction;


Declarations:
CSDBDataContext dc; string ImgPath = “”; byte[] ImgData = null;
Under Form Load:
dc = new CSDBDataContext();
Code under Select Button:
string Value = Interaction.InputBox("Enter Employee No.");
if (int.TryParse(Value, out int Eno)) {
List<Employee_SelectResult> Emp = dc.Employee_Select(Eno, true).ToList();
if (Emp.Count > 0) {
ImgPath = ""; ImgData = null; pictureBox1.Image = null;
textBox1.Text = Emp[0].Eno.ToString(); textBox2.Text = Emp[0].Ename;
textBox3.Text = Emp[0].Job; textBox4.Text = Emp[0].Salary.ToString();

187
if (Emp[0].Photo != null) {
ImgData = Emp[0].Photo.ToArray(); MemoryStream ms = new MemoryStream(ImgData);
pictureBox1.Image = Image.FromStream(ms);
}
}
else { MessageBox.Show("No employee exists with given No."); }
}
else { MessageBox.Show("Employee No. should be integer value."); }
Code under Insert Button:
try {
int? Eno = null;
dc.Employee_Insert(textBox2.Text, textBox3.Text, decimal.Parse(textBox4.Text),
ImgPath.Trim().Length > 0 ? new Binary(File.ReadAllBytes(ImgPath)) : null, ref Eno);
if (Eno != null) { textBox1.Text = Eno.ToString(); ImgPath = ""; }
else {
MessageBox.Show("Failed inserting record into the table.", "Error", MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); }
Code under Clear Button:
ImgPath = “”; ImgData = null;
textBox1.Text = textBox2.Text = textBox3.Text = textBox4.Text = ""; pictureBox1.Image = null; textBox2.Focus();
Code under Close Button:
this.Close();
Code under Update Button:
try {
if (ImgData != null && ImgPath.Trim().Length == 0) {
dc.Employee_Update(int.Parse(textBox1.Text), textBox2.Text, textBox3.Text, decimal.Parse(textBox4.Text),
new Binary(ImgData));
}
else {
if (ImgPath.Trim().Length > 0) { ImgData = File.ReadAllBytes(ImgPath); }
dc.Employee_Update(int.Parse(textBox1.Text), textBox2.Text, textBox3.Text, decimal.Parse(textBox4.Text),
ImgPath.Trim().Length > 0 ? new Binary(ImgData) : null);
}
MessageBox.Show("Record updated in the table.", "Success);
}
catch(Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); }
Code under Delete Button:
try {
dc.Employee_Delete(int.Parse(textBox1.Text)); btnClear.PerformClick();
MessageBox.Show("Record deleted from the table.", "Success");
}
catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); }

188
Code under Load Image Button:
openFileDialog1.FileName = "";
openFileDialog1.Filter = "Jpeg Images (*.jpg)|*.jpg|Bitmap Images (*.bmp)|*.bmp|All Files (*.*)|*.*";
DialogResult dr = openFileDialog1.ShowDialog();
if (dr == DialogResult.OK) {
imgPath = openFileDialog1.FileName;
pictureBox1.ImageLocation = imgPath;
}
Querying data from tables using LINQ to SQL: we can query and retrieve data from table(s) using a query statement
which should be used as following:
from <alias> in <table_name> [<clauses>] select <alias> | new { <list of columns> }

Now drag and drop, Emp and Dept tables under our CSDB database, on LHS panel of OR-Designer. Create a
new form as following, change the DataGridView name as dgView and write the following code:

Declarations: CSDBDataContext dc; bool flag;


Under Form Load: dc = new CSDBDataContext(); dgView.DataSource = from E in dc.Emps select E;
comboBox1.DataSource = (from E in dc.Emps select new { E.Job }).Distinct();
comboBox1.DisplayMember = "Job"; comboBox1.SelectedIndex = -1; flag = true;
Under ComboBox SelectedIndexChanged:
if(flag) { dgView.DataSource = from E in dc.Emps where E.Job == comboBox1.Text select E; }
Under ComboBox KeyPress Event: dgView.DataSource = from E in dc.Emps where E.Job.Contains(comboBox1.Text)
select E;
Under Button1: dgView.DataSource = from E in dc.Emps select new { E.Empno, E.Ename, E.Job, Salary = E.Salary };
Under Button2: dgView.DataSource = from E in dc.Emps orderby E.Salary select E;
Under Button3: dgView.DataSource = from E in dc.Emps orderby E.Salary descending select E;
Under Button4: dgView.DataSource = from E in dc.Emps group E by E.Deptno into G select new
{ Deptno = G.Key, EmpCount = G.Count() };
Under Button5: dgView.DataSource = from E in dc.Emps group E by E.Job into G select new
{ Job = G.Key, EmpCount = G.Count() };
Under Button6: dgView.DataSource = from E in dc.Emps group E by E.Deptno into G where G.Count() > 5 select new
{ Deptno = G.Key, EmpCount = G.Count() };
Under Button7: dgView.DataSource = from E in dc.Emps group E by E.Job into G where G.Count() < 5 select new
{ Job = G.Key, EmpCount = G.Count() };
Under Button8: dgView.DataSource = from E in dc.Emps where E.Job == "Clerk" group E by E.Deptno into G where
G.Count() > 1 orderby G.Key descending select new { Job = G.Key, EmpCount = G.Count() };

189
Under Button9: dgView.DataSource = from E in dc.Emps group E by E.Deptno into G select new
{ Deptno = G.Key, MaxSal = G.Max(E => E.Salary) };
Under Button10: dgView.DataSource = from E in dc.Emps group E by E.Job into G select new
{ Job = G.Key, MinSal = G.Min(E => E.Salary) };
Under Button11: dgView.DataSource = from E in dc.Emps join D in dc.Depts on E.Deptno equals D.Deptno select
new { E.Empno, E.Ename, E.Job, E.Mgr, E.Salary, E.Comm, D.Deptno, D.DName, D.Loc };
Note: Linq doesn’t have having clause, where clause is only provided with the behavior of where as well as having
also. If we use where before group by it works like where and if used after group by it works like having clause.
Assemblies
Assemblies are the building blocks of .NET Framework applications. An assembly is a collection of types and
resources that are built to work together and form a logical unit of functionality. An assembly provides the common
language runtime with the information it needs to be aware of type implementations. To the runtime, a type does
not exist outside the context of an assembly.
Every project after compilation will generate an output file known as assembly. The name of an assembly
file will be same as the project name. The assembly corresponding to a project will be present under
bin\Debug\netcoreapp3.1 folder of that project folder. Assemblies are known as units of deployment because once
the project development is completed what we carry and install on the client systems is the assembly files only. The
extension of an assembly file will be either .exe (executable) or .dll (dynamic link library).
Windows Forms Applications, Console Applications, WPF Applications and Windows Services projects will
generate an .exe assembly. Class Library and Windows Forms Control Library projects will generate a .dll assembly.
Exe assemblies are known as in-process components which were capable of running on their own as well
as provide the support for others to execute. When we work with project templates like Windows Forms
Applications, Console Applications, WPF Applications and Windows Services they generate an exe assembly when
compiled.
Dll assemblies are known as out-process components which were not capable of running on their own they
can only support others to execute. When we work with project templates like Class Library and Windows Forms
Control Library they generate a dll assembly when compiled.
Note: every application is a blend of both .dll’s and .exe assemblies combined together to give better efficiency.

Assemblies are of 2 types:


1. Private Assemblies 2. Shared Assemblies
Private Assemblies:
By default every assembly is private, if reference of these assemblies was added to any project; a copy of
the assembly is created and given to that project, so that each project maintains a private copy of that assembly.

190
Creating an assembly to test it is by default private:
Open a new project of type Class Library and name it as “PAssembly”, which will by default come with a
class Class1 under the file Class1.cs. Now write the following code under the class:
public string SayHello() {
return "Hello from private assembly.";
}
Now compile the project by opening the Solution Explorer, right click on the project and select “Build” which
will compile and generate an assembly with the name as PAssembly.dll.
Note: we can find path of assembly in the output window present at bottom of the studio after build.
Testing the assembly we have created:
Open a new project of type Windows, name it as “TestPAssembly”, place a button on Form and set its text
as “Call SayHello() Method of Class1 in PAssembly.dll”. Now add the reference of PAssembly.dll from its physical
location and write the following code under click of button:
PAssembly.Class1 obj = new PAssembly.Class1();
MessageBox.Show(obj.SayHello());
Run the project to test it, then go and verify under bin/debug folder of current project where we can find a
copy of PAssembly.dll as it is private assembly.

Note: the advantage of a private assembly is faster execution as it was in the local folder, whereas the draw back
was multiple copies gets created when multiple projects adds the reference to consume it.
Shared Assemblies:
If we intend to use an assembly among several applications private assemblies are not feasible, in such
cases we can install it into a centralized location known as the global assembly cache. Each computer where the
common language runtime is installed has this machine-wide code cache. The global assembly cache stores
assemblies specifically designated to be shared by several applications on the computer. All BCL assemblies are
shared .dll assemblies only, so we can find them under GAC. If an assembly is shared multiple copies of the assembly
will not be created even if being consumed by multiple projects, only a single copy under GAC serves all the projects.

Note: administrators often protect the Windows directory using an access control list (ACL) to control write and
execute access. Because the global assembly cache is installed in the Windows directory, it inherits that directory's

191
ACL. It is recommended that only users with Administrator privileges be allowed to add or delete files from the global
assembly cache.

Location of GAC from .Net Framework 3.0: <OS Drive>:\Windows\Microsoft.NET\assembly\GAC_MSIL


How to make an assembly as Shared?
Ans: to make an assembly as Shared we need to install the assembly into GAC.

How to install an assembly into GAC?


Ans: To manage assemblies in GAC like install, un-install and view we are provided with a tool known as Gacutil.exe
(Global Assembly Cache Tool). This tool is automatically installed with VS. To run the tool, use the Visual Studio
Command Prompt. These utilities enable you to run the tool easily, without navigating to the installation folder. To
use Global Assembly Cache on your computer: On the taskbar, click Start, click All Programs, click Visual Studio, click
Visual Studio Tools, and then click Visual Studio Command Prompt and type the following:
gacutil -i | -u | -l [<assembly name>] or gacutil /i | /u | /l [<assembly name>]
What assemblies can be installed into the GAC?
Ans: We can install only Strong Named Assemblies into the GAC.

What is a Strong Named Assembly?


Ans: assemblies deployed in the global assembly cache must have a strong name. When an assembly is added to the
global assembly cache, integrity checks are performed on all files that make up the assembly.

Strong Name:
A strong name consists of the assembly's identity - its simple text name, version number, and public key.
1. Name: it was the name of an assembly used for identification. Every assembly by default has name.
2. Version: software’s maintain versions for discriminating changes that has been made from time to time. As
an assembly is also a software component it will maintain versions, whenever the assembly is created it has
a default version for it i.e. 1.0.0.0, which can be changed when required.
3. Public Key: as GAC contains multiple assemblies in it, to identify each assembly it will maintain a key value
for the assembly known as public key, which should be generated by us and associate with the assembly to
make it Strong Named.

You can ensure that a name is globally unique by signing an assembly with a strong name. In particular,
strong names satisfy the following requirements:
Strong names guarantee name uniqueness by relying on unique key pairs. No one can generate the same
assembly name that you can. Strong names protect the version lineage of an assembly.
A strong name can ensure that no one can produce a subsequent version of your assembly. Users can be
sure that a version of the assembly they are loading comes from the same publisher that created the version the
application was built with.
Strong names provide a strong integrity check. Passing the .NET Framework security checks guarantees that
the contents of the assembly have not been changed since it was built.

Generating a Public Key:


To sign an assembly with a strong name, you must have a public key pair. This public cryptographic key pair
is used during compilation to create a strong-named assembly. You can create a key pair using the Strong Name tool
(Sn.exe) from visual studio command prompt as following:
sn -k <file name> E.g.: sn -k Key.snk

192
Note: the above statement generates a key value and writes it into the file “Key.snk”. Key pair files usually have .snk
extension.
Creating a Shared Assembly:
Step 1: generate a public key. Open VS command prompt, go into your folder and generate a public key as following:
<drive>:\<folder> sn -k key.snk

Step 2: develop a new project and add the key file to it before compilation so that the assembly which is generated
will be Strong Named.
To do this open a new project of type Class Library, name it as “SAssembly” and write the following code
under the class Class1:
public string SayHello() {
return "Hello from shared assembly 1.0.0.0";
}
To associate key file we have generated with the project, open project properties window, select Signing
tab on LHS, which displays a CheckBox as “Sign the Assembly” select it, now in the ComboBox below select browse,
select the key.snk file from its physical location which adds the file under solution explorer, then compile the project
using “Build” option that will generate SAssembly.dll which is Strong Named.

Step 3: installing assembly into GAC by using the “Global Assembly Cache Tool”.
To install the assembly into GAC open Visual Studio Command Prompt, go to the location where
SAssembly.dll was present and write the following:

<drive>:\<folder\SAssembly\SAssembly\bin\Debug\netcoreapp3.1> gacutil -i SAssembly.dll

Step 4: testing the Shared Assembly.


Open a new project of type Windows, name it as TestSAssembly1, place a button on the form and set its
text as “Call SayHello method of Class1 in SAssembly.dll 1.0.0.0”. Now add reference of SAssembly.dll from its
physical location and write the following code under click of button:

SAssembly.Class1 obj = new SAssembly.Class1();


MessageBox.Show(obj.SayHello());

Run the project, test it and verify under bin/debug folder of current project where we will not find any copy
of SAssembly.dll as it is shared assembly.
Versioning Assemblies:
Every assembly is associated with a set of attributes that describes about general info of an assembly like
Title, Company, Description, Version etc. These attributes will be under AssemblyInfo.cs file of each project. To view
them expand properties node under the project in Solution Explorer where we find AssemblyInfo.cs file. We can
change values of any attribute as per our requirements.

Why do we maintain version numbers to an assembly?


Ans: Version no. is maintained for discriminating the changes that has been made from time to time. Version no's
are changed for an assembly if there are any modifications or enhancements made in the code. The default version
of every assembly is 1.0.0.0 and version no is a combination of 4 values like:

193
1. Major Version 2. Minor Version 3. Build Number 4. Revision

What are the criteria for changing the version no. of an assembly?
Ans: we change version no. of an assembly basing on the following criteria:

1. Change the Major version value when we add new types under the assembly.
2. Change the Minor version value when we modify any existing types under the assembly.
3. Change the Build Number when we add new members under types.
4. Change the Revision value when we modify any existing members under types.

Where do we change the version no. of an assembly?


Ans: we need to change the version no. of an assembly under the project file and to do that open Solution Explorer,
right click on the project and select the option “Edit Project File” which opens “SAssembly.csproj” file in XML Format.
Now under <PropertyGroup> tag add the following: <Version>1.0.1.0</Version>
Testing the process of changing version no of an assembly:
Open the SAssembly project we have developed earlier and add a new method under Class1 as following:
public string SayHello2() {
return "Hello from shared assembly 1.0.1.0";
}
Now open “AssemblyInfo.cs” file and change the AssemblyVersion and AssemblyFileVersion attributes to
1.0.1.0, re-build the project and add the new version of SAssembly.dll also into GAC using the Gacutil Tool.

Note: GAC allows placing of multiple versions of an assembly in it and provides different applications using different
versions of the assembly to execute correctly using their required version. Now open the GAC folder where we find
2 versions of SAssembly i.e. 1.0.0.0 and 1.0.1.0

Assemblies and Side-by-Side Execution:


Side-by-side execution is the ability to store and execute multiple versions of an application or component
on the same computer. Support for side-by-side storage and execution of different versions of the same assembly is
an integral part of strong naming and is built into the infrastructure of the runtime. Because the strong-named
assembly's version number is part of its identity, the runtime can store multiple versions of the same assembly in
the global assembly cache and load those assemblies at run time. To test this open a new project of type Windows,
name it as “TestSAssembly2”, place a button on the form and set its text as “Call SayHello2 method of Class1 in
SAssembly.dll 1.0.1.0”. Now add reference of SAssembly 1.0.1.0 version from its physical location and write the
following code under click of button:
SAssembly.Class1 obj = new SAssembly.Class1();
MessageBox.Show(obj.SayHello2());
To check side by side execution of projects run the exe files of TestSAssembly1 and TestSAssembly2 projects
at the same time, where each project will use its required version of SAssembly and execute, as following:

194
In general, an assembly consists of four elements:
• The assembly manifest, which contains assembly metadata.
• Type metadata.
• Microsoft intermediate language (MSIL) code or CIL Code that implements the types.
• A set of resources.

Assembly Manifest: contains information about the attributes that are associated with an assembly like Assembly
Name, Version Number, Culture, Strong Name Information, List of files in the assembly etc.

Type Metadata: describes every type and member defined in your code in a language-neutral manner. Metadata
stores the following information:
• Description of the assembly.
▪ Identity (name, version, culture, public key).
▪ Other assemblies that this assembly depends on.
▪ Security permissions needed to run.
• Description of types.
▪ Name, visibility, base class, and interfaces implemented.
▪ Members (methods, fields, properties, events, nested types).

Metadata provides the following major benefits:


1. Self-describing files, common language runtime modules and assemblies are self-describing.
2. Language interoperability, metadata provides all the information required about compiled code for you to
inherit a class from a file written in a different language.

MSIL Code or CIL Code: during compilation of any .NET programming languages, the source code is translated into
CIL code rather than platform or processor-specific code. CIL is a CPU and platform-independent instruction set that
can be executed in any environment supporting the Common Language Infrastructure, such as the .NET runtime on
Windows, or the cross-platform Mono runtime.

Compilation and Execution Process of a CSharp Project:

195
Software Development
Every software or application we develop will be having 2 parts in it:
1. Front End (Application developed using a Programming Language.)
2. Back End (Data Source where data is stored.)

Application (Front End): for better managing of an application we divide it into 3 different layers as following:
▪ Presentation Layer (UI)
▪ Business Logic Layer (BL)
▪ Data Logic/Access Layer (DL)

Presentation Layer:
▪ Contains all the user interfaces that are required for the application.
▪ The first stage in an application development is designing the UI required for the application.
▪ The presentation layer is a combination of 2 projects i.e. Windows Forms Control Library (.dll) under which
we design all the UI's in the form of UserControls and Windows Forms Application (.exe), the main entry
point of the application.
Note: Never write any logic under the presentation layer to maintain it as lite weight.

Business Logic Layer:


▪ This contains all the code which is required for implementing business rules and this is full of code (logic)
only.
▪ We write the business logic under a separate project i.e. Class Library (.dll).

Data Logic Layer:

196
▪ This contains all the code which is required for managing the data present under the data source and this
is also full of code only.
▪ We write the data accessing logic also under a separate project i.e. Class Library (.dll).

Configuration File: as we are aware that every application requires a configuration file for maintaining application
setting values, it should be present under the exe project only.

Note: while developing an app. make sure we are not developing it as a monolithic unit; it should be better divided
into smaller libraries and then must be integrated as software, as following:

Process of designing Data Logic Layer:


1. Create a Database for storing data.
2. Create tables under the Database representing each entity.
3. Define SP's under the database to perform CRUD Operations on the data present under table.
4. Now under the application in Data Logic Layer add the OR-Designer, drag and drop all the Procedures on
the RHS of the designer which generates all the methods and now those methods can be called from
Presentation Layer.
Step 1: Create Database CompanyDB;

Step 2: Create tables Customer and Employee under the Database.

CREATE TABLE Customer(Custid int CONSTRAINT Custid_PK PRIMARY KEY, FirstName varchar(50) NOT NULL,
LastName varchar(50) NOT NULL, Balance money NOT NULL, Phone bigint NOT NULL, EmailId Varchar(50) NOT NULL,
Address varchar(200) NOT NULL, City varchar(50) NOT NULL, State varchar(50) NOT NULL, PinCode int NOT NULL,
Photo image, Status bit NOT NULL Default 1);

CREATE TABLE Employee(Empno int CONSTRAINT Empno_PK PRIMARY KEY, FirstName varchar(50) NOT NULL,
LastName varchar(50) NOT NULL, Salary money NOT NULL, Phone bigint NOT NULL, EmailId Varchar(50) NOT NULL,
Address varchar(200) NOT NULL, DOJ Date Not Null, DeptName varchar(50) NOT NULL, Location varchar(50) NOT
NULL, Photo image, Status bit NOT NULL Default 1);
Step 3: Define procedures to perform Select, Insert, Update and Delete Operations.
Create Procedure Customer_Select(@Custid int = null, @Status bit = null)
As
Begin

197
If @Custid Is Null And @Status Is Null
Select Custid, FirstName, LastName, Balance, Phone, EmailId, Address, City, State, PinCode, Photo From Customer
Order By Custid;
Else If @Custid Is Null and @Status Is Not Null
Select Custid, FirstName, LastName, Balance, Phone, EmailId, Address, City, State, PinCode, Photo From Customer
Where Status=@Status Order By Custid;
Else
Select Custid, FirstName, LastName, Balance, Phone, EmailId, Address, City, State, PinCode, Photo From Customer
Where Custid=@Custid And Status=@Status;
End;
Create Procedure Customer_Insert(@FirstName varchar(50), @LastName varchar(50), @Balance money,
@Phone bigint, @EmailId Varchar(50), @Address varchar(50), @City varchar(50), @State varchar(50),
@PinCode int, @Photo image, @Custid int out)
As
Begin
Begin Transaction
Select @Custid = IsNull(Max(Custid), 100) + 1 From Customer;
Insert Into Customer (Custid, FirstName, LastName, Balance, Phone, EmailId, Address, City, State, PinCode, Photo)
Values(@Custid, @FirstName, @LastName, @Balance, @Phone, @EmailId, @Address, @City, @State, @PinCode,
@Photo);
Commit Transaction;
End;
Create Procedure Customer_Update(@Custid int, @FirstName varchar(50), @LastName varchar(50),
@Balance money, @Phone bigint, @EmailId Varchar(50), @Address varchar(50), @City varchar(50),
@State varchar(50), @PinCode int, @Photo image)
As
Update Customer Set FirstName=@FirstName, LastName=@LastName, Balance=@Balance, Phone=@Phone,
EmailId=@EmailId, Address=@Address, City=@City, State=@State, PinCode=@PinCode, Photo=@Photo
Where Custid=@Custid;
Create Procedure Customer_Delete(@Custid int)
As
Update Customer Set Status=0 Where Custid=@Custid;
Create Procedure Employee_Select(@Empno int = null, @Status bit = null)
As
Begin
If @Empno Is Null And @Status Is Null
Select Empno, FirstName, LastName, Salary, Phone, EmailId, DeptName, Location, DOJ, Address, Photo From
Employee Order By Empno;
Else If @Empno Is Null and @Status Is Not Null
Select Empno, FirstName, LastName, Salary, Phone, EmailId, DeptName, Location, DOJ, Address, Photo From
Employee Where Status=@Status Order By Empno;
Else
Select Empno, FirstName, LastName, Salary, Phone, EmailId, DeptName, Location, DOJ, Address, Photo From
Employee Where Empno=@Empno And Status=@Status;
End;

198
Create Procedure Employee_Insert(@FirstName varchar(50), @LastName varchar(50), @Salary money,
@Phone bigint, @EmailId Varchar(50), @DeptName varchar(50), @Location varchar(50), @DOJ Date, @Address
varchar(200), @Photo image, @Empno int out)
As
Begin
Begin Transaction
Select @Empno = IsNull(Max(Empno), 100) + 1 From Employee;
Insert Into Employee (Empno, FirstName, LastName, Salary, Phone, EmailId, DeptName, Location, DOJ, Address,
Photo) Values(@Empno, @FirstName, @LastName, @Salary, @Phone, @EmailId, @DeptName, @Location,
@DOJ, @Address, @Photo);
Commit Transaction;
End;
Create Procedure Employee_Update(@Empno int, @FirstName varchar(50), @LastName varchar(50), @Salary
money, @Phone bigint, @EmailId Varchar(50), @DeptName varchar(50), @Location varchar(50), @DOJ Date,
@Address varchar(200), @Photo image )
As
Update Employee Set FirstName=@FirstName, LastName=@LastName, Salary=@Salary, Phone=@Phone,
EmailId=@EmailId, DeptName=@DeptName, Location=@Location, DOJ=@DOJ, Address=@Address,
Photo=@Photo Where Empno=@Empno;
Create Procedure Employee_Delete(@Empno int)
As
Update Employee Set Status=0 Where Empno=@Empno;
Step 4: Now add a new Class Library project under the “BankPro” Solution naming it as “DLProject”, add a OR-
Designer in it naming it as “CompanyDB.dbml”, configure the “CompanyDB” Database under Server Explorer, “Drag
& Drop” all the 8 “Stored Procedures” on RHS Panel of OR-Designer to generate methods to perform CRUD
Operations.
Now under the click of the buttons in the 4 “UserControls”, call the methods to perform select, insert,
update and delete operations.

Note: Under “DLProject” Project we find an “app.config” file and in that we find “<connectionStrings>
</connectionStrings> tag, copy it as it is and paste it into “App.config” file which is present under “MainProject”.

Setup and Deployment


The final stage in the development of an application is deploying the project on client machines, which
should be managed carefully. To organize the things in a proper fashion and install required files on the required
folders we were provided with Setup and Deployment project under .NET. This has to be added under the same
solution where we developed our application.

Note: Before preparing Setup for an application in the top of the Visual Studio we find a ComboBox showing the
options Debug and Release, default will be Debug change it as Release and then right click on the solution node in
solution explorer and Select Build, which will compile all the Projects and re-generates the assemblies again but not
in the “bin\Debug” folder but in “bin\Release” folder and these assemblies will be used in the setup process.
Note: In Visual Studio 2019, Setup Project is not available by default so we need to install it manually and to do that,
in Visual Studio goto “Extensions” Menu and select “Manage Extensions” which will open a new window and in that
Search for “Installer” which will display “Microsoft Visual Studio Installer Projects” with a download button beside,
click on it and download.

199
To add Setup and Deployment Project in our “BankApplication” solution, open “Add New Project” window
and search for “Setup” which displays all “Setup Projects”, select “Setup Project” in it and click next and specify a
name to the Project i.e. “BankSetup” and click “Create”.

When Setup Project is selected and opened it shows the options as following:
❖ File System on Target Machine
➢ Application Folder
➢ User's Desktop
➢ User's Programs Menu

File System on Target Machine in sense the target system where the project is being installed referring to
folders on that machine. Application Folder refers to the project installation folder, which has to be specified while
installing. User's Desktop refers to the desktop folder of target machine. User's Programs Menu refers to the
programs menu folder of target machine.

We can still add other folders referring to the target machine like Program Files, Fonts, and Global Assembly
Cache Folders etc. To add a new folder right click on "File System on Target Machine" and select "Add Special Folder"
which displays a list of options as below, choose the required folder from the list.

200
Now copy the appropriate content into the appropriate folders so that they get installed on the target
machine in appropriate locations. Under Application Folder copy the assemblies (exe’s, dll’s) that has to be installed
on the target machine, to do this right click on the Application Folder and select the option Add => Project Output
as following:

This opens a window showing the list of projects, select the exe project from it:

This will add the necessary exe's, dll's and config file to the project as following:

201
Apart from Project Output we can also choose Folder or File or Assembly and add them under the
Application Folder. Add Folder is used for adding a new folder for storing any images. Add File is used for adding any
help documents. Add Assembly is used for adding any assemblies that are created outside of the solution.

If we want any shortcuts to be created for our application and place them either on desktop or added to
programs menu do the following: Right click on the exe assembly (item of type output) under the application folder
and select "Create Shortcut":

This will create a shortcut specify a name to it.

202
For a shortcut we need to bind an display image of type Icon (.ico), to add an icon image go to the properties
of shortcut => select icon property and select browse from the list, which opens a window => click on browse =>
select application folder => Images folder => click on the add file button => select the image from its physical location
=> click on ok button => again ok button.

Now to place the short cut on desktop or program's menu folder, go to properties of shortcut again and
select the property "Folder" => click on the button beside it which opens a window, from it select user's desktop or
user's programs menu folder which copies the shortcut to the selected folder.

Installation additional user interface dialog boxes:


Setup project provides a number of predefined dialog boxes that you can use to display information or
gather input during an installation. The following is a list of available dialog boxes. Not all dialog boxes are available
for all deployment project types or for Admin installers. To view the current interfaces in the setup go to view menu
=> Editor => Select User Interface.

203
We can still add new user interfaces like Splash, License Agreement, Register User, Read Me, Customer
Information etc. To add a new user interface right click on the node Start => select add dialog which displays the list
of interface, choose what u require. e.g.: Splash, License Agreement.

After adding required user interfaces, we can order them by right clicking on them and select MoveUp
and MoveDown options.

Splash requires a bitmap image to be set that has to be displayed, to set it go to the properties of splash
interface => under SplashBitmap property => select browse => choose an .bmp or .jpg image from its physical
location same as we selected the .ico image previously for the shortcut.
License Agreement and ReadMe requires any .rtf file to be set for displaying, which needs to be added same
as above using the LicenseFile property and ReadMeFile properties of the interfaces.

204
Customer Information will prompt for Name, Organization and Serial Number options; by default Serial
Number Options will not be visible to make it visible set the ShowSerialNumber property as true:

Setting the SerialNumberTemplate property to "<### - %%%%>" creates two text boxes separated by a
dash surrounded by spaces. Validation for the first box (###) simply verifies that the user has entered three digits.
The second box (%%%%) is validated by an algorithm that adds the digits together and divides the sum by 7. If the
remainder is 0, validation succeeds; otherwise, it fails.
After configuring all the things under the Setup project, right click on the SetUp Project in the solution
explorer and Select Build, which will compile all the Projects and prepare's the SetUp File which u can find them
under the SetUp Project’s Release Folder which can is copied to a Disk, and carried to client system for installing.
Note: If the application is associated with a Database, take the back copy of database also to client machines by
copying it on to another Disk.
Installing the Software or Project on Client Machines:
While installing the software on client machines, if the software has to be installed on multiple computers
we need to first configure the “LAN” and on the server machine, install Database software and restore the back-up
of database we have brought. Install .Net Framework on all client machines, install the Project Setup we have
brought on all those machine, open the Config File on all client machines and specify the Connection String taget to
the machine where Database is installed which should finally look as following:

205

You might also like