Some salient features of C#


This article illustrates some of the salient features of C# programming language such as Dictionary.TryGetValue() method, ??, better use of automatic properties, as keyword, object initializers, default keyword, manipulating memory data, use of DEBUG pre-processor directive and many more. I have also mentioned the reason for using these features includeing the sample code. One can leverage these features to improve C# code-writing and deliver more optimized code.

Some good features of C#

1) Dictionary.TryGetValue(K key, out V value)

in general we use:



if(dictionary.ContainsKey(key))
{
value = dictionary[key];
... Statement A...
... Statement B...
}



instead we can use this optimized way:



if(dictionary.TryGetValue(key, out value))
{
... Statement A...
... Statement B...
}




2) ??

This is used to return a default value if some identifier has a null value or reference

in general we use:



int? x = 53;
int y = x;



what if, x has a null value?

use following approach:



int? x = null;
int y = x ?? -1;



3) Flagging the numbers

Different numeric data types can be flagged with some Alphabets to identify their nature.

To identify the nature of numbers we can flag them as under:



double dbl = 30D;
float flt = 35123.5123F;
decimal dcm = 45000.75M; // M cams from "M=Money=Decimal" of old VB
long lng = 12313123123L;
Unsigned long unsl = 18127361231172UL;
Unsigned int unsi = 1812736172U;



4) use of "automatic properties"

in general we use:



private string _name;
...
public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}



Instead we can now use:



public string Name { get; set;}



5) Scope on auto properties

in general we create automatic properties as follow:



public int EmployeeCode
{
get;
set;
}



What if we dont want to set property externally?

We can set the scope of public auto properties...



public int EmployeeCode
{
get;
private set;
}



6) using "as" keyword

in general we use:



EmployInfo emp = (EmployInfo)person;



What-if person object does not contain the object of the type EmployInfo?
1st approach one will throw exception


To handle this, use following approach:



EmployInfo emp = person as EmployInfo;


2nd approach will return null

7) Object Initializers

in general we use:



Employee emp = new Employee();
emp.Name = "John Smith";
emp.StartDate = DateTime.Now();



What-if there are so many properties to set in Employee class

use this Object Initializer:

	

Employee emp = new Employee {Name="John Smith", StartDate=DateTime.Now()} ;



Simple add new property initialization in {..., ..., ...}

8) "default" keyword for generics

in general we use:



T obj = null;



Instead follow this:



T obj = default(T);



2nd approach will assign default value to obj as per the Type of T..

e.g.

null --- if reference type
0 --- if integer type
false --- if boolean, etc.

9) "unions" of memory locations ... Not recommended but one should know this.

Without using pointers or unsafe mode you can manipulate memory space by class members.
Give a try to following code snippet with a console application:



using System;
using System.Runtime.InteropServices;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("\n\nSTATE # 1 (Before manipulation)...\n");
Test test = new Test();
Console.WriteLine(String.Format(" number32 = {0}, number16 = {1}", test.number32, test.number16));
Console.WriteLine(String.Format(" A:{0}, B:{1}, C:{2}, D:{3}, E:{4}, F:{5}, G:{6}, H:{7}", test.A, test.B, test.C, test.D, test.E, test.F, test.G, test.H));

Console.WriteLine("\n\nSTATE # 2 (After this manipulation... set maximum integer value in number32)...\n");
test = new Test { number32 = int.MaxValue };
Console.WriteLine(String.Format(" number32 = {0}, number16 = {1}", test.number32, test.number16));
Console.WriteLine(String.Format(" A:{0}, B:{1}, C:{2}, D:{3}, E:{4}, F:{5}, G:{6}, H:{7}", test.A, test.B, test.C, test.D, test.E, test.F, test.G, test.H));

Console.WriteLine("\n\nSTATE # 3 (More manipulation... set 0 in C and D)...\n");
test.B = test.C = test.D = 10;
test.C = 20;
Console.WriteLine(String.Format(" number32 = {0}, number16 = {1}", test.number32, test.number16));
Console.WriteLine(String.Format(" A:{0}, B:{1}, C:{2}, D:{3}, E:{4}, F:{5}, G:{6}, H:{7}", test.A, test.B, test.C, test.D, test.E, test.F, test.G, test.H));

Console.WriteLine("\n\nSTATE # 4 (More manipulation... set 50 in C and 60 in D)...\n");
test.C = 50;
test.D = 60;
Console.WriteLine(String.Format(" number32 = {0}, number16 = {1}", test.number32, test.number16));
Console.WriteLine(String.Format(" A:{0}, B:{1}, C:{2}, D:{3}, E:{4}, F:{5}, G:{6}, H:{7}", test.A, test.B, test.C, test.D, test.E, test.F, test.G, test.H));

Console.WriteLine("\n\nSTATE # 5 (More manipulation... set 64 in A, B, C, D, E, F, G, H each)...\n");
test.A = test.B = test.C = test.D = test.E = test.F = test.G = test.H = 64;
Console.WriteLine(String.Format(" number32 = {0}, number16 = {1}", test.number32, test.number16));
Console.WriteLine(String.Format(" A:{0}, B:{1}, C:{2}, D:{3}, E:{4}, F:{5}, G:{6}, H:{7}", test.A, test.B, test.C, test.D, test.E, test.F, test.G, test.H));

Console.ReadKey();

}
}

[StructLayout(LayoutKind.Explicit)]
public class Test
{
[FieldOffset(0)]
public byte A; // 1 byre starts from offset 0 in memory

[FieldOffset(1)]
public byte B; // 1 byte starts from offset 1in memory

[FieldOffset(2)]
public byte C; // 1 byte starts from offset 2 in memory

[FieldOffset(3)]
public byte D; // 1 byte starts from offset 3 in memory

[FieldOffset(0)]
public Int32 number32; // 4 bytes starts from offset 0 in memory > 1+1+1+1 = 4 bytes

[FieldOffset(4)]
public byte E; // 1 byre starts from offset 4 in memory

[FieldOffset(5)]
public byte F; // 1 byte starts from offset 5 in memory

[FieldOffset(6)]
public byte G; // 1 byte starts from offset 6 in memory

[FieldOffset(7)]
public byte H; // 1 byte starts from offset 7 in memory

[FieldOffset(4)]
public Int16 number16; // 2 bytes starts from offset 4 in memory > 1+1 = 2 bytes

}
}



Run the application. you may get following output...



STATE # 2 (After this manipulation... set maximum integer value in number32)...

number32 = 2147483647, number16 = 0
A:255, B:255, C:255, D:127, E:0, F:0, G:0, H:0


STATE # 3 (More manipulation... set 0 in C and D)...

number32 = 169085695, number16 = 0
A:255, B:10, C:20, D:10, E:0, F:0, G:0, H:0


STATE # 4 (More manipulation... set 50 in C and 60 in D)...

number32 = 1009912575, number16 = 0
A:255, B:10, C:50, D:60, E:0, F:0, G:0, H:0


STATE # 5 (More manipulation... set 64 in A, B, C, D, E, F, G, H each)...

number32 = 1077952576, number16 = 16448
A:64, B:64, C:64, D:64, E:64, F:64, G:64, H:64


.

This shows that that data manipulation is possible in absolute memory locations. But it is an unsafe operation hence not recommended!

10) using DEBUG pre-processor directive

you can use this directive to take more control on application execution duribng Debugging mode.

eg.



...
...

#if DEBUG
// Place piece of code3 here that will execute during debugging
// - like initializing some variables
// - calling some methods
// - creating some objects
// - writing some log-information
// etc
#endif

...
...





All these tips are taken from http://stackoverflow.com/questions/9033/hidden-features-of-c

More Tips are available on the above link.

Thanks


Comments

No responses found. Be the first to comment...


  • Do not include your name, "with regards" etc in the comment. Write detailed comment, relevant to the topic.
  • No HTML formatting and links to other web sites are allowed.
  • This is a strictly moderated site. Absolutely no spam allowed.
  • Name:
    Email: