0% found this document useful (0 votes)
132 views60 pages

C# Operators

The document discusses the dot operator (.) and namespaces in C#. It explains how the dot operator is used for member access and how namespaces are used to avoid name collisions. It provides an example of creating a class library (DLL) in Visual Studio, including adding methods and properties to a class. Finally, it describes how to add a reference to the DLL in another project to use the classes and methods defined within it.

Uploaded by

Goutham Kamble
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
132 views60 pages

C# Operators

The document discusses the dot operator (.) and namespaces in C#. It explains how the dot operator is used for member access and how namespaces are used to avoid name collisions. It provides an example of creating a class library (DLL) in Visual Studio, including adding methods and properties to a class. Finally, it describes how to add a reference to the DLL in another project to use the classes and methods defined within it.

Uploaded by

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

1|Page

. Operator
The dot operator (.) is used for member access.

System.Console. WriteLine ("hello"); // The class Console in namespace System


s.a = 6;// assign to field a;
s.b(); // invoke member function b;
namespace Example2
{
class Console
{
public static void WriteLine (string s) {}
}
}
namespace Example1
{
using System;
using Example2;
class C
{
void M ()
{
// Console.WriteLine("hello"); // Compiler error. Ambiguous reference.
System.Console. WriteLine ("hello"); //OK
Example2.Console. WriteLine ("hello"); //OK
}
}
}
:: Operator (Scope Resolution Operator)
Basics of namespace imports:
using System;

...

Console.WriteLine("Hello"); //instead of System.Console.WriteLine

But what about having a class with the same name in multiple namespaces?

namespace Sample. First


{
public class Bar { }
}

2|Page
namespace Sample. Second
{
public class Bar { }
}
namespace Demo
{
using Sample. First;
using Sample. Second;
class Program
{
public static void Main()
{
Bar b = new Bar();
}
}
}

error CS0104: 'Bar' is an ambiguous reference between 'Sample.First.Bar' and


'Sample.Second.Bar'.
So, you have to disambiguate by using a full qualified namespace/class notation. Alternatively, you
can define aliases:

namespace Demo
{
using A = Sample. First;
using B = Sample. Second;
class Program
{
public static void Main()
{
A.Bar b = new A.Bar();
}
}
}

Aliases for class names (using Aliases also we create objects)


However, it's a common misbelief that this kind of aliasing only works with namespaces. You
can use it to create an alias for a class as well as shown below:

using System;
using System.Collections.Generic;
using IntList = System.Collections.Generic.List<int>;
using List = System.Collections.ArrayList;
class Program
{
public static void Main()
{
IntList lst = new IntList();

3|Page
Console.WriteLine(lst.GetType());
List lstc = new List();
Console.WriteLine(lstc.GetType());
List<int> lstg = new List<int>();
Console.WriteLine(lstg.GetType());
}
}

Creating a Library Using Visual Studio 2015


Dynamic Link Libraries (DLLs)

we talk about Dynamic Link Libraries (DLLs). Some people also called them C# class libraries.

Creating a DLL (Class Library file) in Visual Studio 2015 preview


https://www.c-sharpcorner.com/UploadFile/66489a/creating-C-Sharp-class-library-dll-
using-visual-studio-2015-pre/

Step 1:
Open your Visual Studio 2015 preview, go to the file menu, go to the new, go with the
project, from the template field select C#, select Class Library then name it as you want. Save it at an
appropriate place. So, from the browse button you can select the appropriate location for saving the
DLL.

Step 2:

After creating this Class Library (DLL) in the Solution Explorer you will see the class. In this
class there is no method and no property at the initial level. This class is totally empty. We will now
add to this class.

4|Page
Step 3:

As I said, there is one class that was generated named Class1. When we double-click on this
class then we see the namespace rizDLL. We use this namespace for the further implementation, in
other words when we create our Windows based program we use this namespace in our program.
When you double-click on the class file you will see something like this.

using System;
using System.Text;
using System.Threading.Tasks;
namespace rizDLL
{
/// <summary>
/// Summary description for Class1.
/// </summary>
public class Class1
{
public Class1() // this is the constructor of class1
{
// Add constructor logic here
}
}
}
Step 4:
After doing this we will check whether everything in our project is okay. So, for checking this
we simply go to the tab menu then select build and click on it.

5|Page
Step5:
When you click on the build solution then in the output window you will see a message that
the build is successful.

Now go to the location where you saved your rizDLL program. Open it, go to the bin folder, go to the
debug folder in the debug folder you will see the DLL file named as you chose when creating the
project. Here my DLL File name is rizDLL.dll.

Step 6:

Now for adding the method and properties in the class file we simply go to the Solution
Explorer then right-click on it and click on view Class Diagram.

When you click you have seen a Class diagram and in that diagram you will see an empty class.

Step 7:
Now here we add a method to our class. For adding the method to our class, we simply right-
click on the class diagram and then we have an option, Add. Click on Add, now there are many
options such as Add Method, Property, Field, Events and many more options.

6|Page
When we click on the Add method then there is a method will Add to our class. Now in the
bottom of our Visual Studio we have options to change the property of this method. Here we add two
methods, one method name is mcTestMethod. In mcTestMethod we do not use any parameters.
Another method name is Add Method, this method has three numbers and returns the sum of those
numbers.

The overall process adds two methods to our class file and the methods look as in the given code.

public void mcTestMethod()


{
throw new System.NotImplementedException();
}
public long Add(long val1, long val2, long val3)
{
throw new System.NotImplementedException();
}

Step 8:

Now we add a property to our class file. To add the property to our class file we simply follow
the same procedure we followed to create the method. Simply go to the class diagram then right-
click on it, click on Add, then click on the property. Here we add a property and name it Extra and
typed it bool and used the public modifier with the get and the set properties.

Step 9:

After Adding the property with the set and get method, add the following code to the class
file. Here I change my class and constructor name, both for convenient implementation. Here we
make the class name and constructor name usedll.

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

7|Page
namespace rizDLL
{
/// <summary>
/// Summary description for Class1.
/// </summary>
public class usedll
{
private bool bTest = false;
public usedll()
{
//
// TODO: Add constructor logic here
//
}

/// <summary>
/// //This is a test method
/// </summary>
public void mcTestMethod()
{

}
/// <summary>
/// //This is a test property
/// </summary>
public bool Extra
{
get
{
return bTest;
}
set
{
bTest = Extra;
}
}

public long Add(long val1, long val2, long val3)


{
return val1 + val2 + val3;
}
}
}

Step 10:
After adding the code successfully, we again build our solution and have a message in the
output window that you have successfully built it. Now you can see your DLL code in your bin/debug
folder.

8|Page
Add DLL file in to the Another Program
Now I will explain how to use the rizDLL in your project. Use the following procedure.
Step 1:
Again, open Visual Studio 2015 Preview, go to the file menu, go to the project, add a new
project then select the template for Visual C# then add a new console application.

Step 2:
After that add the references for the library. So, for this we go to the tab menu of Visual
Studio then go to the tab project then go to the Add Reference command.

9|Page
Step 3:

When you click on Add References you will see a window like this.

Now simply click on the browse button and add the DLL file from the specific position where you
saved it.

Step 4:

After adding the DLL file in your console application, please open the Solution Explorer of
your console application. Explore the references in the references. You will see that DLL file.

10 | P a g e
Step 5:

Now open the class file of the Console Application and add the namespace "using rizDLL".

Then add the following code to your console application file.

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

namespace usingrizDll
{
class Class1
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
usedll cls = new usedll();// object of dll class
long lRes = cls.Add(23, 40,30);
cls.Extra = false;
Console.WriteLine("The sum of your three nos is=" +lRes.ToString());
Console.Read();
}
}
}
Step 6:

11 | P a g e
Now build your Console Application and Run it. After a successful build you will see the
output as in the following picture.

Output:

Compile DLL using Command Line C# Compiler


Introduction

Many users know how to create code library using Visual Studio IDE in GUI environment for
making code reusable code so that multiple application can use that dll. But here I am writing
something by which after reading this article you will be able to compile DLL using just command line
C# compiler without opening Visual Studio IDE.

Language:

C# .net 2.0/3.5

Prerequisites:

Basic knowledge of DOS(cmd.exe) and C#.

Implementation

First let you tell what our target is to compile a DLL (reusable code library) using command
line c# compiler that is csc.exe.

Fire up Notepad or any other your favourite text editor Program.

As example we will build simple dll that will contain methods like add() , substract()
multiply().

using System;

12 | P a g e
namespace SimpleMaths
{
public class Operations
{
public static int add(int a, int b)
{
return a + b;
}
public static int substract(int a, int b)
{
return a - b;
}
public static int multiply(int a, int b)
{
return a * b;
}
}
}
Save the file with <FileName>.cs

Now open Start>>VisualStudio2005/2008 >> Visual Studio tools>>Visual Studio Command


Prompt.
Now in command Prompt Locate the Directory where you have saved the .cs file just created.
Using CD command.
Here I have given myfile name "test.cs".
Now for compiling our dll using csc.exe we need to pass arguments you csc.exe like what
type of file we want to generate, what will be name of output dll file and source file from which we
are building our dll File.

csc /target:library /out:MyMaths.dll test.cs

13 | P a g e
Press Enter and you will get your desired DLL file generated!!

You just have created DLL file with Command Line C# Compiler. Now use that dll file in any .net
project !!

Now you will raise question how do I compile multiple source file (.cs) files?
Well simple just execute command like below one pass 2 names of source files in command
while compiling it.

csc /target:library /out:MyMaths.dll test.cs test2.cs

Example:

// File: Add.cs
namespace UtilityMethods
{
public class AddClass
{
public static long Add (long i, long j)
{
return (i + j);
}
}
}

// File: Mult.cs
namespace UtilityMethods
{
public class MultiplyClass
{
public static long Multiply (long x, long y)
{
return (x * y);
}
}
}

// File: TestCode.cs
using UtilityMethods;
class TestCode
{
static void Main (string [] args)
{
System. Console. WriteLine ("Calling methods from MathLibrary.DLL:");
if (args. Length! = 2)
{
System. Console. WriteLine ("Usage: TestCode <num1> <num2>");
return;

14 | P a g e
}
long num1 = long. Parse (args [0]);
long num2 = long. Parse (args [1]);
long sum = AddClass.Add(num1, num2);
long product = MultiplyClass.Multiply(num1, num2);
System. Console. WriteLine ("{0} + {1} = {2}", num1, num2, sum);
System. Console. WriteLine ("{0} * {1} = {2}", num1, num2, product);
}
}
/* Output (assuming 1234 and 5678 are entered as command-line arguments):
Calling methods from MathLibrary.DLL:
1234 + 5678 = 6912
1234 * 5678 = 7006652
*/

Compile and Execution Process:


1. Create dll file
csc /target: library /out: MathLibrary.DLL Add.cs Mult.cs
2. Create exe file
csc /out: TestCode.exe /reference: MathLibrary.DLL TestCode.cs
3. Run
TestCode 1234 5678
C# Compiler Options
Sample command lines for the C# compiler
 Compiles File.cs producing File.exe:
o csc File.cs
 Compiles File.cs producing File.dll:
o csc -target: library File.cs
 Compiles File.cs and creates My.exe:
o csc -out: My.exe File.cs
 Compiles all the C# files in the current directory with optimizations enabled and defines
the DEBUG symbol. The output is File2.exe:
o csc -define: DEBUG -optimize -out: File2.exe *.cs
 Compiles all the C# files in the current directory producing a debug version of File2.dll. No
logo and no warnings are displayed:
o csc -target: library -out: File2.dll -warn:0 -nologo -debug *.cs
 Compiles all the C# files in the current directory to Something.xyz (a DLL):
o csc -target: library -out: Something.xyz *.cs
NOTE:
|-- Program.cs
|-- Otherfiles.cs
|-- bin
| |-- Debug
| | |-- Newtonsoft.Json.dll
From the top directory, I use the following command to compile:
csc *.cs /r:./bin/Debug/Newtonsoft.Json.dll
--> error CS2001: Source file 'r:bin/Debug/Newtonsoft.Json.dll' could not be found

15 | P a g e
The /reference argument is only used to indicate the name of the assembly.
To specify additional directories to search for assembly files use the /lib argument:
csc *.cs /r:Newtonsoft.Json.dll /lib:"./dir with spaces/need quotes", ./bin/Debug
Use /lib to specify the directory in which one or more of your assembly references is located.
The /lib topic also discusses the directories in which the compiler searches for assemblies.
you should use hyphen (-) instead of front slash
csc -lib:"D:/C# Projects/Lib1/Lib1/bin/Debug" -r:Lib1.dll Program.cs
The other option is
csc -r:"D:/C# Projects/Lib1/Lib1/bin/Debug/Lib1.dll" Program.cs
csc /r:lib1.dll,lib2.dll program.cs
For runtime, you need those referenced dlls in the same folder of your current application.
So, copy those dlls and put it in your current directory and run it.

Extern aliases (ambiguity inside dll files )


Yet another feature are extern aliases.
NOTE: extern alias should be used in side the namespace only
Namespace ConsoleApp{
extern alias lib1;
extern alias lib2;
}
Otherwise we got an error message: An extern alias declaration must precede all other
elements defined in the namespace
Library 1 (lib1.dll)
namespace Bar
{
public class Abc { }
public class Foo { }
}

Library 2 (lib2.dll)
namespace Bar
{
public class Def { }
public class Foo { }
}
Is this valid to do? Yes of course, since we define a class (coincidentally or not) with the same
name "Bar. Foo" in two different assemblies there is no conflict. If you'd compile it into one library
the CS0101 error would pop up (telling you have two identical definitions). However, when you start
both libraries in one single application, problems appear:

using Bar;
class Program
{

16 | P a g e
public static void Main()
{
Foo f = new Foo();
}
}
Using the following command-line compiler invocation:

csc /r:lib1.dll,lib2.dll program.cs


Which Foo should be used? The compiler can't know your intentions. Now assume you haven't
created this ugly situation yourself and you find two libraries which contain a class with the same
name and you want to use both classes at the same time in the same project (a typical example of
Murhpy's Law). The compiler will complain as follows:

error CS0433: The type 'Bar. Foo' exists in both 'c:\temp\lib1.dll' and 'c:\temp\lib2.dll'
There is however a solution to this: extern aliases. Change the program's code as follows:

Not use this statement in below Program “using Bar”.

Here Lib1, Lib2 are alias names of libraries Lib1.dll, Lib2.dll

extern alias Lib1;


extern alias Lib2;
class Program
{
public static void Main ()
{
Lib1::Bar.Foo f1 = new Lib1::Bar.Foo();
Lib2::Bar.Foo f2 = new Lib2::Bar.Foo();
}
}
or
extern alias Lib1;
extern alias Lib2;

using Lib1::Bar;
class Program
{
public static void Main()
{
Foo f1 = new Foo();
Lib2::Bar.Foo f2 = new Lib2::Bar.Foo();
}
}
or
extern alias Lib1;
extern alias Lib2;

using Bar1 = Lib1::Bar;

17 | P a g e
using Bar2 = Lib1::Bar;

class Program
{
public static void Main()
{
Bar1.Foo f1 = new Bar1.Foo();
Bar2.Foo f2 = new Bar2.Foo();
}
}
Compilation should be performed like this:

csc /r:Lib1=lib1.dll /r:Lib2=lib2.dll program.cs


csc /r:lib1=lib1.dll,lib2=lib2.dll program.cs //error CS2034: A /reference option that
declares an extern alias can only have one filename. To specify multiple aliases or filenames,
use multiple /reference options.

Some Changes in Visual Studio 2017 before running above program:


Open solution explorer and select Lib1,Lib2 in the References folder of the project.
When you click on Lib1 Reference->it shows their Properties->in Properties window-
>Change Aliases value ->any name like abc (by default global).
namespace ExternProj
{ “using Bar” is not included when we work on Extern
extern alias abc; alias
extern alias Lib2;
using abc::Bar;
class Program
{
public static void Main()
{
Foo f1 = new Foo();
Lib2::Bar.Foo f2 = new Lib2::Bar.Foo();
f1.show();
f2.show();
}
}
}
Note:
Extern alias: Once you’ve set up an extern alias, there are two different syntax
variations that you can use in qualifying type names from an aliased assembly. You can use
either a colon (:) or a dot (.) after the alias.
extern alias AnotherLib;
class Program

18 | P a g e
{
static void Main()
{
// Syntax variant #1
AnotherLib::DogLibrary.Dog d2 = new
AnotherLib::DogLibrary.Dog("JRT", "Jack");
// Syntax variant #2
AnotherLib.DogLibrary.Dog d3 = new
AnotherLib.DogLibrary.Dog("Rough Collie", "Lassie");
}
}
Scope Resolution Operator (::):
The scope resolution operator :: is used to identify and disambiguate identifiers used in
different scopes.
in C++ the scope resolution operator i.e. :: is used for global variables, whereas in C# it is
related to namespaces.
If you have a type that share an identifier in different namespace, then to identify them use
the scope resolution operator.
For example, to reference System.Console class, use the global namespace alias with the
scope resolution operator
global::System.Console
using myAlias = System.Collections;
namespace Program {
class Demo {
static void Main() {
myAlias::Hashtable h = new myAlias::Hashtable();
h.Add("M", "1");
h.Add("N", "2");
h.Add("O", "3");
h.Add("P", "4");
foreach (string n in h.Keys) {
global::System.Console.WriteLine(n + " " + h[n]);
}
}
}
}
Remarks
The namespace alias qualifier can be global. This invokes a lookup in the global namespace,
rather than an aliased namespace.

The ability to access a member in the global namespace is useful when the
member might be hidden by another entity of the same name.

19 | P a g e
Using System;
class TestApp
{
// Define a new class called 'System' to cause problems.
public class System { }

// Define a constant called 'Console' to cause more problems.


const int Console = 7;
const int number = 66;

static void Main()


{
// The following line causes an error. It accesses TestApp.Console,
// which is a constant.
//Console.WriteLine(number);
}
}
Using System.Console still results in an error because the System namespace is hidden by the class
TestApp.System:

// The following line causes an error. It accesses TestApp.System,


// which does not have a Console.WriteLine method.
System.Console.WriteLine(number);

However, you can work around this error by using global::System.Console, like this:
global::System.Console.WriteLine(number);
Obviously, creating your own namespaces called System is not recommended, and it is
unlikely you will encounter any code in which this has happened. However, in larger projects,
it is a very real possibility that namespace duplication may occur in one form or another. In
these situations, the global namespace qualifier is your guarantee that you can specify the
root namespace.
Using System.Collections;
Hashtable obj=new Hashtable(); //NO ERRORS FOUND
System.Collections.Hashtable test = new System.Collections.Hashtable(); //ERROR: The type
name “Collections” does not exist in the type " TestApp.System”
global::System.Collections.Hashtable test = new global::System.Collections.Hashtable(); //OK

Syntax
:: identifier
class-name :: identifier
namespace :: identifier
enum class :: identifier

20 | P a g e
enum struct :: identifier
Remarks:
The identifier can be a variable, a function, or an enumeration value.

The namespace alias qualifier (: :) is used to look up identifiers. It is always positioned


between two identifiers, as in this example:
global::System.Console. WriteLine ("Hello World");
The namespace alias qualifier can be global. This invokes a lookup in the global
namespace, rather than an aliased namespace.
When the left identifier is global, the search for the right identifier starts at the global
namespace.
using system;
namespace App
{
class System
{
System () { }
Static void Main (string [] args)
{
System.Console. WriteLine ("Amit");
}
}
}
Whenever you compiled this program you will be get an error like Error ’App. System'
does not contain a definition for 'Console'.
In this case we use global keyword to differentiate the class name System and
namespace name System.

namespace App
{
class System
{
System ()
{ }
static void Main (string [] args)
{
global:: System.Console. WriteLine ("Amit");
global:: System.Console. ReadKey (true);
}
}
}

21 | P a g e
using System;
using NS1;
Using MyNS=NS1;
using MyNS = NS1; //alias name.
namespace NS1
{
public class MyClass
{
public void Display ()
{
Console.WriteLine("Display () Method of MyClass in NS1");
}
}
}
public class MyClass
{
public void Display ()
{
Console.WriteLine("Display () Method of MyClass in Global Namespace");
}
}
class UsingMyClass
{
public static void Main ()
{
MyNS::MyClass myObject = new MyNS::MyClass ();
myObject. Display ();
global::MyClass yourObject = new global::MyClass ();
yourObject. Display ();
(OR)
MyClass obj=new MyClass();
Obj.Display();
}
}
Output:
Display () Method of MyClass in NS1
Display () Method of MyClass in Global Namespace
Display () Method of MyClass in Global Namespace

Note: use with alias names only.


MyNS::MyClass obj=new MyNS::MyClass();//ok
NS1::MyClass obj=new NS1::MyClass();// error; error CS0432: Alias `NS1' not found

22 | P a g e
Type Conversion in Expressions:

1. If one operand is decimal, then the other operand is promoted to decimal.


(suppose the second operand is float or double an error comes).
2. If one operand is double, then the other operand is promoted to double.
3. If one operand is float, then the other operand is promoted to float.
4. If one operand is ulong, then the other operand is promoted to ulong. (suppose
the second operand is sbyte, short, int, long an error comes).
5. If one operand is long, then the other operand is promoted to long.
6. If one operand is uint, suppose the second operand is sbyte, short, int both
operands are promoted to long.
7. If one operand is uint, then the other operand is promoted to uint.
8. If one operand is int, then the other operand is promoted to int.
9. If all char, sbyte, byte, short, ushort values are promoted to int. This is called
integer Promotion.

Unary Operators (Increment/Decrement Operators)


1. Increment/Decrement operators works only on Variables not on constant values.
Int y=++x;
Int y=++4; //error.
2. Nesting of Increment/Decrement operators are not allowed.
Int x=4;
Int y=++(++x); //error.
3. Constant variables can’t be increment/decrement.
4. We can apply increment/decrement operator even for floating point datatypes also.
double d=10.5;
d++;
Arithmetic Operators:
+,-,*,/,%
Arithmetic operators follow the following rule
Return type= max (int, operand type a, operand type b);
/ operator:
Remember that when the division operator is applied to an integer type then there
will be no fractional component attached to the result.

6/4=1
6/4.0=1.5
6/(float)4=1.5;

23 | P a g e
6.0/4=1.5
int/int int
int/float float
int/double double
int/char int
Float/int float

1. Integer number divisible by Zero, will get an error.

10/0 Error
0/0 Error
2. For non-zero floating numbers divisible by zero, will get Infinity (+ve or -ve).

10/0.0 Infinity
-10/0.0 - Infinity
10/-0.0 - Infinity
10.34/0 Infinity
3. For Zero floating numbers divisible by Zero, will get NaN.

0/0.0 NaN
0.0/0 NaN
0.0/0.0 NaN
-0/0.0 NaN

0/10 0
0/10.2 0
0.0/10 0

% Operator:
The modulus operator % returns the remainder of a division operator.
********The sign of the remainder is always sign of the numerator only.
10%3 1
-10%3 -1
10%-3 1
12.3%-3.2 2.7
-12.3%-3.2 -2.7
1. Integer number modulus by Zero, will get an error.

10%0 Error
0%0 Error
2. For floating numbers modulus by zero, will get NaN.
10%0.0 NaN
-10%0.0 NaN
10.0%0 NaN
0.0%0 NaN

24 | P a g e
0%0.0 NaN
0.0%0.0 Nan

0%10 0
0%10.2 0
0.0%10 0

Relational Operators:
< , > , <= ,>=
The result type is always Boolean, and we can apply for the primitive types except Boolean.
10 > 20 //False

10.0>20.0 //False

97>’A’ //True

true > false //Error.

5 > true //Error.

Remember
10=10.0f=10.0D

But 10.0M! =10.0F 10.0M! =10.0D 10.0M=10

But 10.2f is different than 10.2D

Nesting of relational operators is not allowed.


10 >30 //false

10>20>40 //error

We can’t apply relational operators to the object references.


“abcd” > “efgh” //error.

Equality Operators:
== !=
We can apply equality operators for both primitives and object references.
10==10.0f //True
‘a’==97 //True
true==true //True
true!=false //True
10.25f==10.25D //False
true!=10 //Error

25 | P a g e
In case of Object references r1,r2
r1==r2 returns true if both r1 and r2 pointing to the same object on heap.
Thread t1=new Thread();

Thread t2=new Thread();

Thread t3=t1;

t1==t2 //false

t1==t3 //true

In order to use == or != operators, both object references must be of the same type.
Thread t1=new Thread();

String s1=”hello”;

t1==s1 //error

t1!=s1 //error.

Object obj=new Object();

t1==obj //false

t1!=obj //true

Here it accepts parent child and child parent relationship.

For any object reference is == null is always false.


t1==null o/p false

Bitwise operators:
&, |,^ can be applicable for both Boolean and integer type.(not in floating type)
~ can be applicable for integer type only. (~x = -(x+1)). (not in floating type)
Char ch=’A’;
Int i=~ch; o/p: -66
Int i=~’A’; o/p: -66
Runtime:
byte a=10;
int c=~a; o/p: -11
byte b=(byte) ~a; o/p: 245 (unexpected value)
byte b=~a; o/p: Error required byte, found int
sbyte b=(sbyte)~a; o/p: -11

Compile Time:
const byte a=10;
int c=~a; o/p: -11
byte b=(byte) ~a; o/p: ERROR (byte not allow -ve values)

26 | P a g e
byte b=~a; o/p: ERROR (byte not allow -ve values)
sbyte b=~a; o/p: -11
 casting is not required because of execution done at compile time.
 Compile time expression evaluate and check the result value fit with result type or not.

! can be applicable for Boolean type only.

Logical Operators:
&& ||
Applicable only for Boolean type.
X && Y X || Y
Here the evaluation of y is optional if it is compulsory then only ‘y’ will be evaluated.
X || Y -> if x is false then only y will be evaluated.
X && Y -> if x is true then only y will be evaluated.
Difference between Bitwise and logical operators:
X&Y X|Y X&&Y X||Y
Both x and y should always be evaluated The evaluation of y is optional. If it is
compulsory then only y will be evaluated.
Applicable for both integer type and Boolean Only Boolean type
type

Assignment Operators:
Single assignment operators: (=)
Int i=’A’;//ok
Ushort s=’B’;//ok
Short s1=’Z’;//Error

double x;
int i;
i = 5; // int to int assignment
x = i; // implicit conversion from int to double
i = (int)x; // needs cast
Console.WriteLine("i is {0}, x is {1}", i, x);
object obj = i;
Console.WriteLine("boxed value = {0}, type is {1}", obj, obj.GetType());
i = (int)obj;
Console.WriteLine("unboxed: {0}", i);

Output:
i is 5, x is 5
boxed value = 5, type is System.Int32

27 | P a g e
unboxed: 5
Compound assignment operators:
+=,-=,*=,/=,%= <<=,>>=,>>>=,&=,|=,^=
Chained assignment operators:
Int a, b, c, d;
a=b=c=d=100; //ok
int a, b, c, d, a=b=c=d=100;//error
Int a,b;
int a=b=c=d=100; //error.
a=10 , b=20; //error
a=10;b=20; //OK
Int a, b, c, d;
int a=10,b=20; //ok
a=b=c=d=20;
a+=b-=c*=d/=2;
WriteLine (a+” “+b+” “+c+” “+d);
d=d/2=20/2=10;
Int a,b,c;
c=c*d=20*10=200;
Int d=3,e=4,f=5;
b=b-c=20-200=-180;
Int a, byte b;//error
a=a+b=20+(-180)=-160
o/p: -160 -180 200 10

Runtime Assignment chart:


Byte a=10;
Short b=a; //ok
sbyte byte short ushort char int uint long ulong float double decimal
sbyte
byte
short
ushort
char
int
uint
long
ulong
float
double
decimal

Note: Constant variables assignment done at compile time only.


Const int i=10;
byte j=i;//ok
Const long i=10;
byte j=i;//error

28 | P a g e
At compile time direct assignment is done with the following steps.
1. Check base on result type, the values are within the group type range or not.
Int a=10;
Const byte b=a; //CE: Expression being assigned to b must be constant.
//THIS TYPE OF ASSIGNMENT IS NOT ALLOWED IN C#.Because Constant values
assignment done at compile time.

Const int a=10;


Const byte b=a; //ok
Below table shows the details about constant variable to another constant variable.

Result Type Allowed types


Sbyte, byte, short, ushort, char Same Return type + common int type.
Int Int type+below datatypes
Sbyte,byte,short,ushort, char
Uint Uint +same family int+ int is
common+below unsigned types
byte,ushort,char
Long Long to below datatypes
byte,sbyte,short,ushort,int,uint,char
Ulong Ulong+same family long+ int is common
+below unsinged types byte,ushort,char.
Float Float types + all numeric types
Double Double+ float+ all numeric types
Decimal Decimal+ all numeric types

Runtime initialisation:
int i=10;
byte j=i; // i should be of same type.
Console.WriteLine(j);// error CS0266: Cannot implicitly convert type `int' to `byte'.

Examples
Const byte b1=100;
Const sbyte b2=100;
Const short b3=100;
Const ushort b4=100;
Const int b5=100;
Byte c=b1; //ok . because same type
Byte c=b2; //error.
Byte c=b3; //error
Byte c=b4; //error

29 | P a g e
Byte c=b5; //ok. Because int type.

Conditional operators: ?:
int x =(10>20)?10:20;

Here values should be of result type.

Constant Expression:
Constant expression evaluated at compile time;
1. The compiler first checks the values of range based on group type.
2. Check based on result type, the two variables are with in the group type or not.
byte b= (10>20)?122:20; //OK
byte b=(10>20)?1222L:20;//Error
byte b=(10>20)?10.2:20;//Error
3. Evaluate the expression, after evaluation, we get true or false value. Based on this value, we
check true or false block, value is fitted with result type or not.
byte b=10>20?127:128;//Error
byte b=10<20?127:128;//Ok
byte b=10.2<20.7?127:128;//Ok

Variable Expression:
Variable expression evaluated at Runtime.
byte b=x>y ? val1: val2;
1. When val1,val2 are constant values. i.e. directly given the value
byte b=x>y ? 10: 20;
a. Compiler first checks the values of ranges based on group type.
b. The compiler takes the integer values as int type without specify any literal type.
byte b=i>j?10:20;//10,20 as int type
2. When val1,val2 are variables.
a. val1,val2 should be result type compulsory.
byte b=(byte)((10>20)?122:20); //ok 20

int a=10;
int b=20;
byte v=(a>b)?122:20;//error :error CS0266: Cannot implicitly convert type `int' to `byte'.

int a=10;
int b=20;
byte c=100;
byte v=(a>b)?a:c; //error here a and c both are promoted to higher datatype int.
error CS0266: Cannot implicitly convert type `int' to `byte'.

int a=10;
int b=20;

30 | P a g e
byte c=100;
byte v=(a>b)?c:c; //ok both are of result type.

Null Coalescing (??) Operator in C#


 The ?? operator is called the null-coalescing operator
 It's used to define a default value for nullable value types or reference types
 It returns the left-hand operand if the operand is not null
 Otherwise it returns the right operand

Compile-Time Errors and Exceptions


 A nullable type can contain a value, or it can be undefined.
 The ?? operator defines the default value to be returned when a nullable type is
assigned to a non-nullable type.
 If you try to assign a nullable value type to a non-nullable value type without using
the ?? operator, you will generate a compile-time error.
int? x = null;//x is nullable value type
int z = 0;//z is non-nullable value type
z = x;

But if you use ?? operator. You won't have any problem.


z = x ?? 1;//with ?? operator No issues
 If you use a cast, and the nullable value type is currently undefined,
an InvalidOperationExceptionexception will be thrown
int? x = null;//x is nullable value type
int z = 0;//z is non-nullable value type
z = (int)x;//when you run the app,

//It'll give ==>


But If you use ?? operator, you won't have any problem.
z = x ?? 1;//with ?? operator No issues
 The result of a ?? operator is not considered to be a constant even if both its arguments
are constants

Example
class Program

31 | P a g e
{
static void Main(string[] args)
{
//EXAMPLE 01 :
int? x = null;
// y = x, unless x is null, in which case y = -1
int y = x ?? -1;
//EXAMPLE 02 : ?? Operator with Value Type Assign i to return value of
method, unless return value is null, in which case assign default value of int to i
int i = GetNullableInt() ?? default(int);
//EXAMPLE 03 : ?? Operator with Reference Type
string s = GetStringValue();
// Assign content of s to z, unless s is null, in which case assign "Unspecified"
var z = s ?? "Unspecified";
}
static int? GetNullableInt()
{
return null;
}
static string GetStringValue()
{
return null;
}
}
Output:
Example 01

Example 02

Example 03

int? a=null;
int b=a; // Compile Time: error CS0266: Cannot implicitly convert type `int?' to `int'.

int? a=null;
int b=a. Value; //Runtime Error: System. InvalidOperationException: Nullable object must have a value.

int? a=10;
int b=a; // Compile Time: error CS0266: Cannot implicitly convert type `int?' to `int'.

int? a=10;
int b=a. Value; (or) int b=(int)a;

32 | P a g e
Usage of ?? Operator
 The chaining is a big plus for the ?? operator. It removes a bunch of redundant IFs

string finalVal = parm1 ?? localDefault ?? globalDefault;


 You can easily convert nullable value types into non-nullable types.
int? test = null;
var result = test ?? 0; //now the result is int, not nullable int?
 You can use null-coalescing operator in lazy instantiated private variables
private IList<Car> _car;
public ILis<Car> CarList
{
get { return _car ?? (_car = new List<Car>()); }
}

The C# Null Coalescing Operator (??) is a binary operator that simplifies checking for
null values. It can be used with both nullable types and reference types. It is represented as x
?? y which means if x is non-null, evaluate to x; otherwise, y.
 x is the first operand which is a variable of a nullable type.
 y is the second operand which has a non-nullable value.
While executing code, if x evaluates to null, y is returned as the value. Also remember that
the null coalescing operator (??) is right-associative which means it is evaluated from right to
left. So, if you have an expression of the form x ?? y ?? z, this expression is evaluated as x??
(y?? z).
Now with an overview of the C# Null Coalescing operator, let us see how to use the Null
coalescing operators in practical scenarios.
Scenario 1 – Assign a Nullable type to Non-Nullable Type
Consider the following piece of code where we are assigning a nullable type to a non-
nullable type.

In the code above, if the nullable type (‘a’) has a null value and is assigned to a non-nullable
type ( ‘b’), an exception of type InvalidOperationException is thrown, as shown below:

33 | P a g e
One way to resolve this error is to use IF..ELSE condition and check the value of the nullable
type before assigning it to the non-nullable type

The code will now compile and give you desired results. However, using the null coalescing
operator in such scenarios, you can create clearer code than the equivalent if-else statement,
as shown below:

In the code shown above, if ‘a’ has been assigned a non-null value, then this value
will be assigned to the int b. However, since the nullable type ‘a’ has been assigned null, the
value to the right of the operator (??) i.e. zero will be assigned to b instead.
The value of b if printed, is 0.
byte? a=10;
sbyte b=a??0; // Cannot implicitly convert type 'byte' to 'sbyte'.
Scenario 2 – Initializing instance fields in a Struct
You cannot declare instance field initializers in a Struct. The following piece of code:

gives a compilation error: cannot have instance field initializers in structs

34 | P a g e
However, using the Null coalescing operator, you can use a work-around as follows:

The value A can now be accessed and will return 1. Quite a handy technique using the
Nullable type and the Null Coalescing operator!
There are some more ways the Null-coalescing operator can be used. I have covered some
basic uses in my article Different Ways of using the C# Null Coalescing Operator.
Here’s a simple example of using the Null-Coalescing operator
int? i = null;
int j = i ?? 2;
// here the resultant value of j is 2
Here are some additional ways of using the Null-Coalescing operator in your code.

Method 1
string address = homeAddress1 ?? homeAddress2 ?? officeAddress ?? "No Address";
returns the first non-null value in this long expression. This expression returns “No
Address” if homeAddress1, homeAddress2 and officeAddress are Null.

Method 2
While converting a Nullable Type to Non-Nullable type, we do an explicit cast to avoid
assigning null values to a non-nullable type, as shown below:
int? a = NullType(); // returns nullable int
int b = (int)a;
instead you can avoid the explicit cast using a null-coalescing operator and write:
int? a = NullType();
int b = a ?? 0;

Method 3
private IList<Person> person;
public IList<Person> PersonList
{
get
{
return person ?? (person = new List<Person>());
}
}
Typical usage of the null-coalescing operator in a lazy instantiated private variable.

35 | P a g e
Method 4

string conn = Connection["TestMachineStr1"] ?? AppConnection["ProdMachineStr2"]


?? DefaultConnection["DefaultConn"];

NULL Conditional Operator in C# 6.0


NULL conditional operator or NULL propagation operator was introduced with C# 6.0.
There are 2 syntaxes for NULL conditional operator, which are given below.
 NULL conditional operator for member access (?.)
 NULL conditional operator for index-based access (?[)
So, the first syntax “?.” is being used very popularly but the second syntax “?[” is used by very
few people. But I am going to cover all those in this blog.
NULL conditional operator for member access (?.)
Have a look at the code snippet given below.
static void Main(string[] args)
{
string name = null;
int length = name. Length;
}
The preceding code snippet will throw an exception NullReferenceException.

If I use the NULL conditional operator (?.), then the preceding code snippet can be written as
given below.
static void Main(string[] args)
{
string name = null;
int? length = name?. Length;
}
It will run successfully without throwing any exception.

36 | P a g e
NULL conditional operator for member access (?.) with null-coalescing operator (??)
if you do not want to make the length variable as Nullable int type, then you can use null-
coalescing operator (??) with “?.” Follow the code snippet given below for the same.
static void Main(string[] args)
{
string name = null;
int length = name?. Length ?? 0;
}

More useful example with complete code is given below.


using static System.Console;
namespace NULLConditionalOperatorExample
{
class Program
{
static void Main(string[] args)
{
Customer cust = new Customer { Id=101};
WriteLine($"Customer id: {cust.Id} & name: {cust.Name??"N/A"}");
WriteLine($"Customer name contains {cust.Name?.Length ??0} character(s)");
}
}
class Customer
{
public int Id { get; set; }
public string Name { get; set; }
}
}
NULL conditional operator for index-based access (?[)
Have a look at the code snippet given below.
string[] arr1 = new string[] { "one", "two", "three" };
arr1=null;
string s1=arr1?[0];
Console.WriteLine(s1??"Null value");
static void Main(string[] args)
{
int[] Numbers = { 1, 2, 3, 4, 5 };
Numbers = null;
WriteLine($"5th element is: {Numbers[4]}");
}
The preceding code snippet will throw an exception NullReferenceException.

37 | P a g e
If I use the NULL conditional operator (?[), then the preceding code snippet can be written, as
given below.
static void Main(string[] args)
{
int[] Numbers = { 1, 2, 3, 4, 5 };
Numbers = null;
WriteLine($"5th element is: {Numbers?[4]}");
}
It will run successfully without throwing any exception.
In previous versions null checking for any kind of objects manually we need to write if
condition then we need to write our required properties or else we need to write our business
logic.
If(Object != null)
{
If(Object. User != null)
{
return object.User.Name;
} Else
{
return null;
}
}
Another way of checking null condition using ternary operator (Single line if statement) as
follows:
return object!=null? (object. User!=null?object.User.Name:null):null;
Now In c# 6.0 Microsoft is coming up with a new null-conditional operator that helps you
write these checks more sufficiently as follows
return object?. User?. Name;
Note: If object is null then it won’t navigate to nested object.
Before we explain this feature, let's see why we need this feature. Assume we have a class
with two properties.
38 | P a g e
public class UserData
{
public String Username { get; set; }
public String Password { get; set; }
public String Token { get; set; }
}
We create an instance of this class but do not assign any value to the Token property. So, it
will be NULL. So, in our code, when we use these properties, we add the NULL check for the
Token property.
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
UserData _userData = new UserData();
_userData.Username = "User1";
_userData.Password = "TestPassword";
if (_userData.Token == null)
Console. Write ("Token not provided");
else
Console. Write ("Token Initialized");
Console.ReadKey();
}
}
public class UserData
{
public String Username { get; set; }
public String Password { get; set; }
public String Token { get; set; }
}
}
Look's good and works fine. With C# 6.0, this NULL check process is made more simplified. In
order to check any value, we can simply use the convention:
instanceName?.PropertyName
Confused? Let's replace the preceding convention with the code instanceName => userData
and PropertyName => Token. So, we change our code to C# 6.0 and check the NULL using the
preceding convention. So, our code becomes:
using static System.Console;
namespace NullOperator
{
class Program

39 | P a g e
{
static void Main(string[] args)
{
UserData _userData = new UserData();
_userData.Username = "User1";
_userData.Password = "TestPassword";
Console. Write (_userData?.Token?? “Token Not Initialised”);
Console.ReadKey();
}
}
public class UserData
{
public String Username { get; set; }
public String Password { get; set; }
public String Token { get; set; }
}
}
So, what we did is, we simply add "?" to check the value of the Token and write it to
the Console, if it is available else do nothing. Let's add the binary operator to print the message
if no token is available. So, we simply add the message as:
Console. Write (_userData?.Token ?? "Token not provided");
using System;
class Program
{
static string _name;
/// Property with custom value when null.
static string Name
{
get {return _name ?? "Default";}
set {_name = value;}
}
static void Main()
{
Console.WriteLine(Name);
Name = "Perls";
Console.WriteLine(Name);
Name = null;
Console.WriteLine(Name);
}
}
Output:
Default
Perls
Default

40 | P a g e
string userName = "Banketeshvar Narayan";
userName = null;
if ((username?. Length??0)>20)
WriteLine("UserName cannot be more than 20-character long.");
else
WriteLine("UserName length is: {0}", username?. Length??0);

Type information Operators Is ,as, sizeof, typeof


sizeof(x) returns the size of the value type x. Remarks: The sizeof operator can be applied only to
value types, not reference types..
sizeof(int);
sizeof(long);
typeof(T) returns a System. Type object describing the type. T must be the name of the type, and
not a variable. Use the GetType method to retrieve run-time type information of
variables.
class Program
{
static Type _type = typeof(char); // Store Type as field.
static void Main()
{
Console.WriteLine(_type); // Value type pointer
Console.WriteLine(typeof(int)); // Value type
Console.WriteLine(typeof(Stream)); // Class type
Console.WriteLine(typeof(TextWriter)); // Class type
Console.WriteLine(typeof(Array)); // Class type
Console.WriteLine(typeof(int[])); // Array reference type
}
}
Output
System. Char
System.Int32
System.IO.Stream
System.IO.TextWriter
System. Array
System.Int32[]

IS / AS OPERATORS:
Look at the example given below:
Circle c = new Circle (32);
object o = c;
int i = (int)o;// it compiles okay but throws an exception at runtime

41 | P a g e
Here the runtime is more suspicious; if the type of object in memory does not match the cast,
the runtime will throw an InvalidCastException.

IS Operator
IS Operator is used to Check the Compatibility of an Object with a given Type and it
returns the result as a Boolean i.e. True or False. True if given object is compatible with new
one, else false.
Example:

using System;
class Class1
{
}
class Class2
{
}
public class IsTest
{
public static void Test (object o)
{
Class1 a;
Class2 b;
if (o is Class1)
{
Console.WriteLine("o is Class1");
a = (Class1) o;
}
else if (o is Class2)
{
Console.WriteLine("o is Class2");
b = (Class2) o;
}
else
Console.WriteLine("o is neither Class1 nor Class2.");
}
public static void Main ()
{
Class1 c1 = new Class1();
Class2 c2 = new Class2();
Test(c1);
Test(c2);
Test ("Passing String Value instead of class");
}
}

42 | P a g e
Object obj = new Object (); // Creates a new Object obj
// checking compatibility of obj object with other type
Boolean b1 = (obj is Object); // b1 is set to true.
Boolean b2 = (obj is Employee); // The cast fails: no exception is thrown, but b2 is set to false.
//we can also use it
if (obj is Employee)
{
Employee emp = (Employee) obj; // TO DO:
}

In above, CLR is checking the obj object type twice. First time with in the if condition and if it
is true, with in the if block. This way affects the performance since every time CLR will walk the
inheritance hierarchy, checking each base type against the specified type (Employee). To avoid this,
we have AS operator.

If the reference of the given object is null, the IS operator will return false since there is no object
available to check its type.

Object obj=null;
bool b=obj is Object;
Console.WriteLine(b); //False

AS Operator
As Operator is used for Casting of Object to a given Type. It returns non-null if given
object is compatible with new one, else null. In this way AS operator help you to do safe type
casting. The above code can be re-written by using AS operator in a better way.

Object obj = new Object (); // Creates a new Object obj


// checking compatibility of obj object with other type
Employee emp = obj as Employee; // The cast fails: no exception is thrown, but emp is set to null.
if (emp! = null)
{
// TO:DO
}

43 | P a g e
If the reference of the given object is null, the AS operator will return NULL since there is no object
available to check its type.

In this way, CLR is checking the obj object type only one time. Hence AS operator provide good
performance over IS operator. Now if you want to use emp object then it will throw
NullReferenceException as given below.

Object obj = new Object ();


Employee emp = obj as Employee; // try to Cast obj to an Employee
// The above cast fails: no exception is thrown, but emp is set to null.
emp. ToString (); // Accessing emp throws a NullReferenceException.
using System;

class Class1{
}
class Class2{
}
public class IsTest
{
public static void Main ()
{
object [] myObjects = new object [6];
myObjects [0] = new Class1();
myObjects [1] = new Class2();
myObjects [2] = "string";
myObjects [3] = 32;
myObjects [4] = null;
for (int i = 0; i < myObjects.Length; ++i)
{
string s = myObjects[i] as string;
Console. Write ("{0}:", i);
if (s! = null)
Console.WriteLine("'" + s + "'");
else
Console.WriteLine("not a string");
}
Console.ReadKey();
}
}

Overflow exception control

44 | P a g e
Expression Explanation
checked(a) uses overflow checking on value a
unchecked(a) avoids overflow checking on value a

new operator:
We can divide the use of the "new" keyword into the following uses:
 An operator
 A modifier
 A constraint
new as an operator
It is used to create objects and invoke a constructor.
Using the "new" operator, we can create an object or instantiate an object, in other words
with the "new" operator we can invoke a constructor.

Let's create a class for example:


public class Author
{
public Author()
{
}
public Author(string firstName, string lastName, int rank)
{
FirstName = firstName;
LastName = lastName;
Rank = rank;
}
public int num;
public string FirstName { get; set; }
public string LastName { get; set; }
public int Rank { get; set; }
new public string FullName()
{
return string.Format("{0} {1}", FirstName, LastName);
}
}
Initialize a class:
//We can instantiate or invoke a constructor
var author = new Author();
Initialize collections:
//we can initialize a collection

45 | P a g e
var authors = new List<Author>();
Create an instance of anonymous types:
//anonymous can also be initialized by new
var authorAnonymous = from auth in authors
select new { FullName = string. Format ("{0} {1}", auth.FirstName, auth.LastName) };

An important thing to notice is that with the use of the "new" operator we can invoke the
default constructor of a value type.
Int num = new int(); //think about this

Interesting point

We cannot overload the "new" operator.

It will throw an exception if it fails to allocate memory. Think of a scenario where it does fail.

Declaring a default constructor for a struct results in an error. The reason is that every value
type implicitly invokes its default constructor.

The following is wrong:


Public struct MyStruct
{
Public MyStruct() { }
Public int num1;
}
The "new" operator only assigns the memory and does not destroy memory that depends upon
the scope.

Value-types objects, like int, are created on the stack and reference type objects like "Author"
are created on the heap.

The new as a modifier

It hides a member that is inherited from a base class.

So, what does this mean?


It simply replaces the base class version.

What happens if I do not use "new"?


So, in this case your code runs perfectly with a compiler warning that you are hiding
without using the "new" modifier.

There will be an error if you use both "new" and "override" on the same member.

46 | P a g e
The following is wrong:

public class BaseAuthor


{
public class Author
{
public virtual string FullName()
{
return string.Format ("{0} {1}", FirstName, LastName);
}
}
}
public class DerivedAuthor:BaseAuthor
{
new public override string FullName()
{
return string.Format("{0} {1}", FirstName, LastName);
}
}
Here we are hiding the base class in the derived class:

public class BaseAuthor


{
public class Author
{
public virtual string FullName()
{
return string.Format("{0} {1}", FirstName, LastName);
}
}
}
public class DerivedAuthor:BaseAuthor
{
new public class Author
{
public virtual string FullName()
{
return string.Format("{0} {1}", FirstName, LastName);
}
}
}
Now, we can invoke the parent and derived classes as:

Author = new Author();

47 | P a g e
BaseAuthor.Author = new BaseAuthor.Author();

"new" as a Constraint

It specifies that the generic type must have a public parameter less constructor. The "new"
constraint cannot be used on an abstract type.

public class AuthorFactory<T> where T : new()


{
public T GetAuthor()
{
return new T();
}
}
Now, we can initialize the preceding as:
var factoryAuth = new AuthorFactory<Author>();
To get an instance of the preceding type:
var objAuth = factoryAuth.GetAuthor();
If using multiple constraints then the "new" constraint must be last:
public class AuthorFactoryComparable<T>
where T : IComparable, new()
{
//logic goes here
}

Simple example
If a method Test() is declared in the base class A and classes B or C has no methods as
shown below.
using System;
class A
{
public void Test() { Console.WriteLine("A::Test()"); }
}
class B : A { }
class C : B { }
class Program
{
static void Main(string[] args)
{
A a = new A();

48 | P a g e
a.Test(); // output --> "A::Test()"
B b = new B();
b.Test(); // output --> "A::Test()"
C c = new C();
c.Test(); // output --> "A::Test()"
}
}
Output: No errors and No Warranting’s
A::Test()
A::Test()
A::Test()

Remember:
class Bike{
void run(){System.out.println("running");}
}
class Splender extends Bike{
void run(){System.out.println("running safely with 60km");}
public static void main(String args[]){
Bike b = new Splender();//upcasting
b.run();
}
}
Output: running safely with 60km.

Suppose you have Test () method in all the classes A, B, C as shown below:

using System;
class A
{
public void Test() { Console.WriteLine("A::Test()"); }
}
class B : A
{
public void Test() { Console.WriteLine("B::Test()"); }
}
class C : B
{
public void Test() { Console.WriteLine("C::Test()"); }
}
class Program
{
static void Main(string[] args)
{
A a = new A();
B b = new B();

49 | P a g e
C c = new C();
a.Test(); // output --> "A::Test()"
b.Test(); // output --> "B::Test()"
c.Test(); // output --> "C::Test()"

a = new B();
a.Test(); // output --> "A::Test()"

b = new C();
b.Test(); // output --> "B::Test()"
}
}
When you will run the above program, it will run successfully and gives the O/P. But this program will
show the two warnings as shown below:
'B.Test()' hides inherited member 'A.Test()'. Use the new keyword if hiding was intended.
C.Test()' hides inherited member 'B.Test()'. Use the new keyword if hiding was intended.

The method should be `virtual` in the base class if you want child classes to be able to
override it. The warning you're getting is indicating that, the base class is not virtual, you
cannot override it, you can only shadow it. By applying the `new` modifier you aren't
changing any behaviour, you're just indicating that the method is shadowing, not overriding,
the base class. Since you don't want to shadow it, you want to override it, you need to
modify the base class to make the method virtual. The warning can't specify that as the
solution though, as in many cases the user won't have the ability to change the base class
definition.

Method Hiding (new keyword) or Method Shadowing (Shadowing is VB


Concept):
Method Hiding is the concept of hiding the base class function into the derived class.
Method Hiding can be achieved by using new keyword. The new keyword is used to hide a
method, property, indexer, or event of base class into derived class.
As you have seen in the above example the compiler generates the warnings since C#
also supports method hiding. For hiding the base class method from derived class simply
declare the derived class method with new keyword. Hence above code can be re-written as :

using System;
class A
{
public void Test() { Console.WriteLine("A::Test()"); }
}
class B : A
{
public new void Test() { Console.WriteLine("B::Test()"); }

50 | P a g e
}
class C : B
{
public new void Test() { Console.WriteLine("C::Test()"); }
}
class Program
{
static void Main(string[] args)
{
A a = new A();
B b = new B();
C c = new C();

a.Test(); // output --> "A::Test()"


b.Test(); // output --> "B::Test()"
c.Test(); // output --> "C::Test()"

a = new B();
a.Test(); // output --> "A::Test()"

b = new C();
b.Test(); // output --> "B::Test()"
}
}
Moreover, if you are expecting the fourth and fifth output should be "B:: Test ()" and "C::
Test ()" since the objects a and b are referenced by the object of B and C respectively then
you must re-write the above code for Method Overriding.

new keyword denotes that we define a new method with the parent class name.

Keyword “new” can be used with keyword “virtual” also.


If Keyword “new” is used in derive class then derive method hided by parent method. As
shown in below program:

Parent can hold the reference to its child, but Child cannot hold the reference to
its parent.

51 | P a g e
Virtual and Overridden Methods
Only if a method is declared virtual, derived classes can override this method if they
are explicitly declared to override the virtual base class method with the override keyword.

class A
{
public virtual void Foo() { Console.WriteLine("A::Foo()"); }
}

class B : A
{
public override void Foo() { Console.WriteLine("B::Foo()"); }
}

class Test
{
static void Main(string[] args)
{
A a;
B b;

a = new A();
b = new B();
a.Foo(); // output --> "A::Foo()"

52 | P a g e
b.Foo(); // output --> "B::Foo()"

a = new B();
a.Foo(); // output --> "B::Foo()"
}
}
}
Combining Method Overriding and Hiding
Methods of a derived class can both be virtual and at the same time hide the derived
method. In order to declare such a method, both keywords virtual and new have to be used
in the method declaration:
class A
{
public void Foo() {}
}

class B : A
{
public virtual new void Foo() {}
}

A class C can now declare a method Foo() that either overrides or hides Foo() from class B:
class C : B
{
public override void Foo() {}
// or
public new void Foo() {}
}
Conclusion
 C# is not Java.
 Only methods in base classes need not override or hide derived methods. All methods
in derived classes require to be either defined as new or as override.
 Know what you’re doing and look out for compiler warnings.
Important Points About Keywords Virtual and Override
In C#, if you like to override the parent class method then you must mark the parent
method by keyword “Virtual” and method in derived class which intended to override the
parent method should be marked by keyword “override”.
Note:
 If parent method is marked by keyword “Virtual” but child is not marked by keyword
“override”, then program will compile but the parent method will not be override. A
warning came. (CS0114: `Child.drive()' hides inherited member `Parent.drive()'.)

53 | P a g e
 If Child method is marked by keyword “override” but parent method is not marked by
keyword “virtual” then program will not compile. It will give following error:
‘TestB. display ()’: cannot override inherited member ‘TestA. display ()’ because it is not marked
virtual, abstract, or override.

How to call base class method with override:


In some scenario, we need base class functionality also while overriding the method of that
class. C# provides that functionality with ‘base’ keyword. For that I have changed code of
class B like following.

public class B:A


{
public override void Print()
{
System.Console.WriteLine("Override Print method from b");
base. Print();
}
}
class Program
{
static void Main(string[] args)
{
B b=new B();
b.Print();
}
}

This article explains the main differences among overriding, hiding and shadowing in C#.
I am mainly focusing on the main points and not detailed descriptions. So, you will finish this
very quickly. Also, some examples to understand the concepts better are provided.
1. The "override" modifier extends the base class method, and the "new" modifier hides
it.
2. The "virtual" keyword modifies a method, property, indexer, or event declared in the
base class and allows it to be overridden in the derived class.
3. The "override" keyword extends or modifies a virtual/abstract method, property,
indexer, or event of the base class into the derived class.
4. The "new" keyword is used to hide a method, property, indexer, or event of the base
class into the derived class.
5. If a method is not overriding the derived method then it is hiding it. A hiding method
must be declared using the new keyword.
6. Shadowing is another commonly used term for hiding. The C# specification only uses
"hiding" but either is acceptable. Shadowing is a VB concept.
What are the differences between method hiding and overriding in C#?

54 | P a g e
1. For hiding the base class method from derived class simply declare the derived class
method with the new keyword.
Whereas in C#, for overriding the base class method in a derived class, you need to
declare the base class method as virtual and the derived class method as overridden.
2. If a method is simply hidden then the implementation to call is based on the compile-
time type of the argument "this".
Whereas if a method is overridden then the implementation to be called is based on
the run-time type of the argument "this".
3. New is reference-type specific, overriding is object-type specific.
What are the differences between method hiding and method shadowing?
1. Shadowing is a VB concept. In C#, this concept is called hiding.
2. The two terms mean the same in C#.
Method hiding == shadowing
3. In short, name "hiding" in C# (new modifier) is called shadowing in VB.NET (keyword
Shadows).
4. In C# parlance, when you say "hiding" you're usually talking about inheritance, where
a more derived method "hides" a base-class method from the normal inherited
method call chain.
5. When you say "shadow" you're usually talking about scope; an identifier in an inner
scope is "shadowing" an identifier at a higher scope.
6. In other languages, what is called "hiding" in C# is sometimes called "shadowing" as
well.

55 | P a g e
Method hiding with warning

56 | P a g e
Example 3: Overriding, Hiding and Shadowing

57 | P a g e
58 | P a g e
Example 4 : Method Overriding and Method Hiding:

59 | P a g e
Upcasting or Generalization or Widening:
Converting from differ types (individual) to common type.
Placing sub class memory into super class reference variable.
Downcasting or Specialization or Narrowing
Converting from common type to individual type.
Placing sub class memory into sub class reference variable by using cast operator,
which is pointing by superclass reference.

Class A{
Int i=10;
 Non-Static Variables
}
 Static methods
Class B extends A{ Using obj  Static Variables
Int m=20; you can
} access
Class Test{ supper
Public void Main(){ class
A obj=new B();//Upcasting
Console.WriteLine(obj.i);//10
Console.WriteLine(obj.m);// error not accessible
B obj2=(B) obj; //Downcasting
Console.WriteLine(obj2.m);// 20

}
} Using obj  Non-Static methods
you can
access in
sub class

60 | P a g e

You might also like