Sunday, September 21, 2014

C# 5.0 and .NET Framework some basic key points summary - Part 3

Continuing the post...



C# Loops
for (int i = 0; i < length; i++)
{
}
foreach (var item in collection)
{
}
do
{
} while (true);
while (true)
{
}


Conditional constructs and equality
No more C/C++ style comparing to non 0. Everything must be resolved to bool in a condition statement.
string[] myArray = { "str1", "str2", "str3" };
var result = from el in myArray select el;
if (result.ToList().Count > 0)
{// works
}
if (result.ToList().Count)
{//doesn't work
}


Switch statement
  1. Unlike Java/C++ there is no fall-through (Motivation: error-free code). The code below will not compile
    MyEnum val = MyEnum.Value1;
switch (val)
{
case MyEnum.Value1:
System.Console.WriteLine("value1");
case MyEnum.Value2:
case MyEnum.Value3:
System.Console.WriteLine("value2");
break;
default: break;
}
  1. Unlike C++/Java, the enumeration type must be specified
  2. Unlike Java (Java 7 has it already), you can switch over String, but with a decrease in performance
    String switchVar = "str1";
switch (switchVar)
{
case "str1":
break;
case "str2":
break;
case "str3":
break;
default:
break;
}
  1. Fall-through can be simulated using goto keyword
    MyEnum val = MyEnum.Value1;
switch (val)
{
case MyEnum.Value1:
System.Console.WriteLine("value1");
goto case MyEnum.Value3;
case MyEnum.Value2:
case MyEnum.Value3:
System.Console.WriteLine("value2");
break;
default: break;
}
Method with different type of parameters, with parameter modifiers (ref, out, params)
/// <summary>
/// Example of method with different type of parameters
/// </summary>
/// <param name="p1">Passed by reference</param>
/// <param name="p2">Passed by reference</param>
/// <param name="p3">Passed by value</param>
/// <param name="mC">Passed by reference</param>
/// <param name="mS">Passed by value</param>
/// <param name="morePs">params. More parameters grouped in a single array</param>
public void ParamExample1(out int p1, ref byte p2, String p3, MyClass mC, MyStruct mS, params Object[] morePs)
{
// out must be always assigned before returning from this method.
// Compile error otherwise
p1 = 7;
// ref assigned by the caller and optionally reassigned by the called method.
p2 = 3;
p3 = "test_string";
Console.WriteLine(morePs.Length); // 2
mC.var1 = 9;
mC.var2 = true;
mS.var1 = 2;
mS.var2 = 0;
}


Methods and parameters

Optional parameters
/// <summary>
/// Method with optional parameters
/// </summary>
/// <param name="optStr">if you don't set it, you cant set optObj</param>
/// <param name="optObj">if you want to set it, you must set optStr</param>
public void ParamExample2(String optStr = "somestr", Object optObj = null)
{
Console.WriteLine(optStr);
Console.WriteLine(optObj);
// Any assignment inside this scope will not affect the object
// in outer scope unless you set some of its properties
optObj = new Object();
}

Ref parameter modifier on a reference type
/// <summary>
/// If you declare such a method, you are able to change inside such
/// method the object the outer scope reference references to... :)
/// </summary>
/// <param name="refToRef"></param>
public void ParamExample3(ref Object refToRef)
{
refToRef = new MyClass();
((MyClass)refToRef).var1 = 1234;
((MyClass)refToRef).var2 = true;
}

Named parameters example
/// <summary>
/// Method to show named parameters example
/// </summary>
/// <param name="param1"></param>
/// <param name="param2"></param>
public void ParamExample4(MyClass param1, MyStruct param2)
{
Console.WriteLine(param1.var1); // 9
Console.WriteLine(param1.var2); // True
Console.WriteLine(param2.var1); // 0
Console.WriteLine(param2.var2); // 0
}

The main method (and types declarations) that uses all the methods from above
public static void RunExample()
{
Program prog = new Program();
int param1; // Initialized to 0
byte param2 = 4;
String param3 = "before_assign";
MyClass myClass = new MyClass();
MyStruct myStruct = new MyStruct();
prog.ParamExample1(out param1, ref param2, param3, myClass, myStruct, "4235", 4);
Console.WriteLine(param1); // 7\n
Console.WriteLine(param2); // 3\n
Console.WriteLine(param3); // "before_assign"
Console.WriteLine(myClass.var1); // 9\n
Console.WriteLine(myClass.var2); // True\n
Console.WriteLine(myStruct.var1); // 0\n
Console.WriteLine(myStruct.var2); // 0\n
prog.ParamExample2(); // somestr,\n\n (New line in console)
prog.ParamExample2("optStr"); // optStr,\n\n
prog.ParamExample2("optStr2", param1); // optStr2,\n7
//prog.paramExample2(new DateTime()); // You can't do that
Console.WriteLine(param1); // 7
Object objEx3 = DateTime.Now;
prog.ParamExample3(ref objEx3);
Console.WriteLine(objEx3); // 1234True
// named parameters example. All named parameters must be listed at the
// end of the method if starting with positional parameters
// Output is: 9\nTrue\n0\n0\n
prog.ParamExample4(param2: myStruct, param1: myClass);
//Usefullness of named parameters: in conjunction with optional parameters
// Output is: somestr\nSystem.Object\n
prog.ParamExample2(optObj : new Object());
Console.ReadLine(); // Waiting the user to press Enter
}
public class MyClass
{
public int var1;
public bool var2;
public override String ToString()
{
return var1.ToString() + var2.ToString();
}
}
public struct MyStruct
{
public Int64 var1;
public Int32 var2;
public void DisplayValues()
{
Console.WriteLine(var1);
Console.WriteLine(var2);
}
}


Method Overloading
A method is said to be overloaded if you have multiple identically named methods with different number of parameters or with different parameter types. Note that only a different return type results in a compiler error.


C# Arrays
An array is a set of data accessed using a numerical index.

Initialization of the arrays
/// <summary>
/// Example of arrays in C#. Index starts at 0 in C#
/// </summary>
public static void ArraysInitializationExample()
{
// Just some test data
int i1 = 8;
double d1 = 7.7;
Object obj1 = new Object();
// 1.
// Array elements are initialized to the default values
int[] intsArray = new int[10];
intsArray[0] = i1;
//intsArray[10] = 6; // This will result in an IndexOutOfRangeException
// 2. Implicitly typed local array
// The size is determined from the number of elements and the elements must
// be implicitly convertible to the array type
var stringArray = new String[] { "str1", "str2", "str3" };
// 3.
// The size is constant and the elements must be implicitly convertible
// to the array type
Object[] objArray = new Object[3] { new int(), d1, obj1 };
// Output is: 0\n7.7\nSystem.Object
foreach (Object obj in objArray)
{
Console.WriteLine(obj);
}
// 4.
// The type is inferred from the best match for all given elements.
// If none found, "No best type found for implicitly typed array" is shown
var forthArray = new[] { 4.5, 6.7, 5 };
// 5.
// Syntax available only in a declaration (Data type specified)
Single[] dblArray = { 5.7f, 6.6f };
// 6.
// Initializing an one dimensional array using System.Array,
// and spefifying the desired type. You can also create a multi-dimensional array
Int16[] int16Array = (Int16[])Array.CreateInstance(typeof (Int16), 4);
int16Array[0] = 1; int16Array[1] = 2; int16Array[2] = 3; int16Array[3] = 4;
// Output is: 1234
for (int i = 0; i < int16Array.Length; i++)
{
Console.Write(int16Array.GetValue(i));
}
Console.ReadLine();
}

System.Array
This is an abstract class that provides many useful methods that tend to simplify your work with the arrays. For instance, you can: Clear(), Copy(), IndexOf(), Reverse(), Sort() etc.


Enums in C#
An enum is a custom data type of name/value pairs.
Standard enum definition
public enum MyEnum
{
ENUMVAL1, // 0
ENUMVAL2, // 1
ENUMVAL3, // 2
ENUMVAL4, // 3
ENUMVAL5 // 4
}
Custom enum order
In an enum where the elements are not sequential, and the user doesn't specify some of the enum values, the compiler fills the gaps automatically.
public enum MyCustomOrderEnum
{
ENUMVAL1 = 9,
ENUMVAL2 = 0,
ENUMVAL3, // 1
ENUMVAL4 = 4,
ENUMVAL5 // 5
}
Underlying type of the enums
By default, the underlying type of an enum is Int32. However, you can specify another type from the set (byte, sbyte, short, ushort, int, uint, long, ulong). Yes, you can't use String (A hack available).
public enum MyByteEnum : byte
{
BYTEENUMVAL1 = 45,
BYTEENUMVAL2 = 37,
BYTEENUMVAL3// = 256 This will result in a compiler error, byte 0-255
}
If you want to have strings in enumeration, you can do something like this:
public enum MyStringEnum
{
[StringValue("This is value 1")]
VALUE1 = 0,
[StringValue("This is value 2")]
VALUE2 = 1,
[StringValue("This is value 3")]
VALUE3 = 3
}
public class StringValueAttribute : System.Attribute
{
private String value;
public StringValueAttribute(string value)
{
this.value = value;
}
public String Value
{
get { return value; }
}
}
The biggest drawback is that to access this value, you have to type a lot of code:
MyStringEnum mSE = MyStringEnum.VALUE1;
StringValueAttribute[] strValueAttr = mSE.GetType().GetField(mSE.ToString()).GetCustomAttributes(typeof(StringValueAttribute), false) as StringValueAttribute[];
if (strValueAttr.Length > 0)
{
Console.WriteLine(strValueAttr[0]);
}
If you want to automate this code, you can make it an extension
public static class StringValueAttributeExtension
{
public static String GetStringAttribute(this Enum value)
{
var sva = (trainingTestProject.Program.StringValueAttribute[])(value.GetType().GetField(value.ToString())).GetCustomAttributes(typeof(trainingTestProject.Program.StringValueAttribute), false);
return sva.Length > 0 ? sva[0].Value : value.ToString();
}
}
Then you can call it by using:
Console.WriteLine(mSE.GetStringAttribute());
Another approach is to declare a sealed class [1].
The System.Enum type provides many methods to work with enums, the most used ones being GetValues() - used to retrieve the values in the enum, that can be cast to obtain the value in the underlying data type, GetNames() - which returns the names of the values of the enum,


Structures (Structs)[Structs_Info]
Structures are lightweight classes that support encapsulation, but that cannot be used for inheritance. Data in a struct usually must be accessed through public properties, but created as private. As with classes, you can define custom constructors.
public struct MyStruct2
{
private Int64 var1;
private Int32 var2;
public Int32 Var2 { get { return var2; } set { var2 = value; } }
public Int64 Var1 { get { return var1; } set { var1 = value; } }
public void DisplayValues()
{
Console.WriteLine(var1);
Console.WriteLine(var2);
}
}
public static void StructExample()
{
// Compiler error.
// The values of the struct must be assigned before use
/*MyStruct2 myStruct2;
myStruct2.DisplayValues();*/
// Compiler error. For some reason, the compiler doesn't understand
// that you've assigned the fields
/*MyStruct2 myStruct2_1;
myStruct2_1.Var1 = 10;
myStruct2_1.Var2 = 20;
myStruct2_1.DisplayValues(); // 10\n20\n*/
// OK, compiler understands that you've assigned all the values
MyStruct myStruct;
myStruct.var1 = 10;
myStruct.var2 = 20;
myStruct.DisplayValues(); // 10\n20\n
// In this case default values are assigned by the constructor
MyStruct2 myStruct2_2 = new MyStruct2();
myStruct2_2.DisplayValues(); // 0\n0\n
Console.ReadLine();
}


Value Types, Reference types and assignment operator
publicFONT> static void ValueRefTypesExample()
{
MyStruct myStruct1;
myStruct1.var1 = 1;
myStruct1.var2 = 5;
MyStruct myStruct2 = new MyStruct();
myStruct2 = myStruct1;
myStruct1.var1 = 2;
// Because when assigning one ValueType to another,
// a member-by-member copy operation is done, changes to one
// instance will not be reflected to another one, they are independent
Console.WriteLine(myStruct2.var1); // 1
Console.WriteLine(myStruct2.var2); // 5
// Classes are reference types. When assigning one ref type to another,
// the reference is updated, and the object points to the newly assigned
// Object in memory, so changes to one object will be applied to
// another object
MyClass myClass1, myClass2 = new MyClass();
myClass2.var1 = 8;
myClass2.var2 = true;
myClass1 = myClass2;
myClass1.var1 = 4;
Console.WriteLine(myClass2.var1); // 4
Console.WriteLine(myClass2.var2); // true
Console.ReadLine();
}


Value Types containing Reference Types
If a Value Type contains a Reference Type, the copying law is the following:
  • Value Types are copied by value
  • Reference type are copied by reference
So in fact you can think of this as a shallow copy.
If you need a deep copy, you must implement ICloneable.

References: