Tuesday, January 9, 2018

Feature Differences

Trying to explain the Differences between some of the important features of C# with examples.

Differences between Var, Dynamic and Object

var is used to store an anonymous type or a collection of anonymous types, and scope limited to within the declared method. Dynamic type variables type checking is done at run-time and can be initialized by any type of data. Object is basically a block of memory that has been configured according to the blueprint.

Var Dynamic Object

Can store any type but mandatory to initialize the var type at the time of declaration

Can store any type of the variable

Can store any kind of value as this is the base for all types in .NET

It is type safe as compiler has all information of the stored value. No issues are run time

It is not type safe as compiler won't have any information until run time about variable type

Compiler has little information about the type

The scope of this type is limited to where it is defined. Neither be passed as argument nor used as return type

This can be passed as argument as well as can be used as method return type

This can be passed as argument as well as can be used as method return type

Casting is not required at anytime as compiler has all the information

Casting is not required but should be aware of properties and methods related to the stored type

Casting is required to original type to use it and perform operations

No problems as compiler has all the information

Causes problems, If wrong properties or methods are accessed as all the information will be resolved at run time

Causes problem at run time if the value is not getting converted to base data type

Introduced in C# 3.0 and useful cases of anonymous type scenarios

Introduced in C# 4.0 and useful in cases of working with Reflection, COM or dynamic languages

Introduced in C# 1.0 and sseful in cases where we don't know any information about the type

Collections and Collection Interfaces

Collections: Collection refers to a set of objects. These can grow and shrink dynamically as the objects added or deleted. Collection is basically a class, so needs to be declared before one can add elements to that. System.Collections namespace contains below collections:

  • ArrayList: Represents an array of objects whose size is dynamically increased or decreased as required. It supports add or remove methods for adding and removing objects from the collection.
  • Hashtable: Also represents a collection of objects which are stored in key/value pair, where key is a hash code and value is an object. Using key one can access the objects in the collection. Also supports add and remove methods for adding and removing objects from the collection.
  • SortedList: This collection is a combination of ArrayList and Hashtable and along with can be sorted by the keys. It can be accessible by key or by index. Also supports add and remove methods for adding and removing objects from the collection.
  • Stack: Represents a LIFO (Last In First Out) collection of objects. It supports Push and Pop methods for adding and removing objects from the collection.
  • Queue: Represents a FIFO (First In First Out) collection of objects. Supports Enqueue and Dequeue methods for adding and removing objects from the collection.

Collection Interfaces: All the collection types use common interfaces which define the basic functionality for each collection class. Below are the key collection classes. IEnumerable acts as a base interface for all the collection types which is extended by ICollection which is further extended by IDictionary and IList interfaces. All collection interfaces are not implemented by all the collections. It depends on the nature of collection.

  • IEnumerable: Provides an enumerator which supports a simple iteration over a non generic collection
  • ICollection: Defines size, enumerators and synchronization methods for all nongeneric collections
  • IDictionary: Represents nongeneric collection of key/value pairs
  • IList: Represents nongeneric collection of objects that can be individually accessed b index
Virtual, Override, and New keywords

All these three keywords will help support working with Polymorphism which is nothing but method overriding and method overloading. Virtual and Override keywords support method overriding whereas New keyword supports method hiding.

Virtual: this keyword lets a method, property, indexer or event declared in the base class to be overridden or modifying the functionality in the derived class.

Override: this keyword lets to extend or modify a base classes method, property, indexer or event in derived class.

New: this keyword lets to hide a method, property, indexer or event declared in the base class in to derived class.

  • Virtual and Override causes late binding and is called as runtime poluymorphism. This takes same name as base class with same parameters
  • New causes early binding and also called as compile time polymorphism. This takes same name as base class with different parameters
Type Casting or Type Conversion

This is a mechanism to convert one data type value to another data type, and is possible only if both the data types are compatible to each other. Otherwise InvalidCastException will be thrown. Below are the different type of conversions:

  • Implicit Conversion: This is being handled automatically by the compiler with no data lose. This is safe type conversion and includes converting smaller to larger data types as well as derived classes to base classes. This is also called as Upcasting.
  • Explicit Conversion: This is being done by using a cast operator. In this type of conversion data might be lost or conversion might not be succeed for some reasons and not an type safe conversion. Also supports converting smaller to larger data types as well as derived classes to base classes. This is also called as Downcasting.
  • User-defined Conversion: This conversion is performed by using special methods that you can define to enable explicit and implicit conversions. In this type, all conversions methods must be declared as static. It includes conversion of class to struct or basic data type and struct to class or basic data type.
Is vs As

IS and AS operators are helpful to handle the exceptions occurred during casting / converting one data type to another data type. These are helpful to do a safe type casting. Usually exceptions occur when the new data type is not compatible with the given object data type.

IS Operator: This operator checks whether both given object and the new object type is compatible or not. It returns boolean (True / False) value as a result. In case of a given object is null, this will return false as there is no object to check for type. The drawback of using this operator is, the Performance. As every time CLR checks for each base type with the specified type following the inheritance hierarchy. Below is how to use IS operator:

Object obj = new Object(); // Creates a new Object
Boolean isCompatible = (obj is Organization); // No exception in this case but sets isCompatible as False
If (isCompatible) { Organization org = (Organization) obj; }

( OR )

if (obj is Organization) { Organization org = (Organization) obj; }

AS Operator: Like IS operator, AS operator also helps to check the type of a given object is compatible with new object type. Instead of boolean, this returns NON-NULL if given object is compatible else NULL as result. This operator performs only reference conversions, nullable conversions and boxing conversions, and cannot perform user-defined conversions. Using this, CLR checks object type for only one time. So, AS operator provide good performance over IS operator.

Object obj = new Object(); // Creates a new Object obj
Organization org = obj as Organization; // This cast fails, but no exception is thrown and org will set to NULL
If (org != null) { // Execute your code here }
Boxing and Unboxing

These always refers to the allocation of a value on the Heap rather than on the Stack.

Boxing: Refers to an Implicit conversion of a value type to a reference type. Basically in this process, a value type is being allocated on Heap rather from Stack

Unboxing: Refers to an Explicit conversion of a reference type to a value type. Basically in this process, a reference type is being allocated back to Stack from Heap

int curValue = 12; // value type which will be created on Stack
Object retBoxed = curValue;
int retUnboxed = (int) retBoxed; // Unboxed from heap to Stack

  • Try to eliminate using Boxing as it slows down the performance and increases memory usage
  • NullReferenceException will be thrown by compiler in case of unboxing a null
  • InvalidCastException will be thrown by compiler in case of unboxing a reference type to an incompatible value type

Constant, ReadOnly and Static
Constants: These must be assigned a value at the time of declaration and after that they cannot be modified.
  • These are Static by default, so no need to declare them using static keyword
  • They must have a value at compilation time
  • Can be declared within functions and be used as Attributes
  • These can be declared as pubic, private, protected, internal or protected internal access modifiers
ReadOnly: These can be initialized either at the time of declaration or with in the constructor of the defined class.
  • Must have set the value by the time constructor exists
  • As these are not static by default, one need to define them using static keyword if they want this type of variable to be static
  • Will be evaluated when instance is created
  • Use this modifier when one want to make a field constant at run time
  • ReadOnly can be applied to Value and Reference types but not to delegates and events
Static: This is used to specify a static member, meaning these are common to all the objects and they do not tied up to a specific object.
  • Evaluated when code execution hits class reference ie. when new instance is created or a static method is executed
  • Must have a value by the time the static constructor is done
  • These can be used with classes, fields, methods, properties, operators, events and constructors, but no on indexers, destructors or other than classes
When to use what:
  • If we know the value will never ever change use const
  • If we re unsure that the value will change, and you don't want other classes or code to be able to change it, use readonly
  • If we need a field to be a property of a type, and not a property of an instance of that type, use static
ref and out parameters

Both ref and out parameters are used to pass an argument within a method.

ref: the ref keyword is used to pass an argument as a reference, which means that when a value of the parameter is changed then it gets reflected in the calling method. An argument which is passed using a ref keyword must be initialized in the calling method before it is passed to the called method.

public static string GetNextName(ref int id)
{
string returnText = "Next-" + id.ToString();
id += 1;
return returnText;
}
static void Main(string[] args)
{
int i = 1;
Console.WriteLine("Previous value of integer i:" + i.ToString());
string test = GetNextName(ref i);
Console.WriteLine("Current value of integer i:" + i.ToString());
}

out: the out keyword is also used to pass an argument like ref but can be passed without assigning any value to it. An argument that is passed using an out keyword must be initialized in the called method before it returns back to calling method.

public static string GetNextNameByOut(out int id)
{
id = 1;
string returnText = "Next-" + id.ToString();
return returnText;
}
static void Main(string[] args)
{
int i = 0;
Console.WriteLine("Previous value of integer i:" + i.ToString());
string test = GetNextNameByOut(out i);
Console.WriteLine("Current value of integer i:" + i.ToString());
}