Sunday, September 21, 2014

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

Continuing the post

System.Environment Class
Exposes methods to get passed in command line arguments even if the main method does not specify input parameters (GetCommandLineArgs()), method to show environment details (ShowEnvironmentDetails()), Logical drives, OS version, Processor count etc...

System.Console Class
Encapsulates input, output and error-stream manipulations for console-based applications. (Beep, Title, BufferHeight/Width, WindowHeight,W,T,L, Clear)
Formatting Output:
Console.WriteLine(“{0}, Number {1}, Number {0}; {1}, Number {1}”, 9, 10);
Formatting with String Format Character
Console.WriteLine("The value 99999 in various formats:");
Console.WriteLine("c format: {0:c}", 99999); // Currency
Console.WriteLine("d9 format: {0:d9}", 99999); // Decimals, with number of digits
Console.WriteLine("f3 format: {0:f3}", 99999); // Fixed point, with number of digits
Console.WriteLine("n format: {0:n}", 99999); // Basic numerical formatting
Console.WriteLine("E format: {0:E}", 99999); // Exponential notation, uppercase
Console.WriteLine("e format: {0:e}", 99999); // Exponential notation, lowercase
Console.WriteLine("X format: {0:X}", 99999); // Hexadecimal, uppercase
Console.WriteLine("x format: {0:x}", 99999); // Hex, lowercase
Console.WriteLine("g/G format: {0:g}", 99999); // General, number to fixed or exp
c format: $99,999.00
d9 format: 000099999
f3 format: 99999.000
n format: 99,999.00
E format: 9.999900E+004
e format: 9.999900e+004
X format: 1869F
x format: 1869f
g/G format: 99999
In non console applications, use String.Format(“”, params...) to achieve the same effect!

System Data Types:
CLS compliant: bool, byte, short, int, long, char float, double, decimal, string, Object
Non CLS compliant: sbyte, ushort, uint, ulong
Declaration: by default a floating-point number is considered double, unless f/F suffix is present (7.7f). To declare a decimal, use m/M, for long l/L.
Local variable declaration:
int tmpInt = 0;
Int32 tmpInt2 = 0;
String tmpString = "", tmpString2;
tmpString2 = "";
bool tmpBool = true, tmpBool2 = tmpBool;
System.Boolean boolTmp3 = false;
// Intrinsic data types using default constructor
Int32 tmpInt3 = new Int32();
int tmpInt4 = new int();
double tmpDouble = new double();
float tmpFloat = new Single();
DateTime tmpDateTime = new DateTime();

Value Type data types:[ValueType_info] derive from ValueType, which in turn derives from Object. Any type that derives from ValueType is an enum or struct inside, not a class.
Because structures are derived from ValueType, they are allocated on the stack, so the creation and the destruction happens much faster than with the objects allocated on the heap. The lifetime is determined by the defining scope, so when the structure falls out the defining scope, it is removed from memory immediately, in comparison with the heap, where the lifetime is controlled by the garbage collector.

As stated in Pro C# 5.0 by Andrew Troelsen, functionally, the only purpose of System.ValueType is to override the virtual methods defined by System.Object to use value-based, versus reference-based, semantics.
The list:
  1. Boolean
  2. Byte
  3. Char
  4. Decimal
  5. Double
  6. Int16
  7. Int32
  8. Int64
  9. Sbyte
  10. UInt16
  11. UInt32
  12. UInt64
  13. Void
  14. DateTime
  15. Guid
  16. TimeSpan
  17. Single
  18. Enumerations and Structures
Reference Type data types: derive directly from Object. Are allocated on the heap
The list:
  1. Type
  2. String
  3. Array
  4. Exception
  5. Delegate
  6. MulticastDelegate
Nullable types
Nullable types are Value types that allow null assignment. The list (incomplete):
  1. int?
  2. double?
  3. bool?
  4. char?
  5. value type arrays (int?[], double?[],...)
  6. (All other value types listed above here)
The ?? operator (the null-coalescing operator)
This operator is the compact version of the if/else condition
Example from MSDN:
class NullCoalesce
static int? GetNullableInt()
return null;
static string GetStringValue()
return null;
static void Main()
int? x = null;
// Set y to the value of x if x is NOT null; otherwise,
// if x = null, set y to -1.
int y = x ?? -1;
// Assign i to return value of the method if the method's result
// is NOT null; otherwise, if the result is null, set i to the
// default value of int.
int i = GetNullableInt() ?? default(int);
string s = GetStringValue();
// Display the value of s if s is NOT null; otherwise,
// display the string "Unspecified".
Console.WriteLine(s ?? "Unspecified");

Equality of Value Types: The value is compared, true returned if the values are equal
Equality of Reference Types: True is returned if the references point to the same object
Equality of Strings: Even if the string is a reference type, the equality operator has been redefined and values of strings are compared instead

Difference between Int32 and int is just one of preference for readability and code appearance/style. The "int" notation is just a shorthand notation to Int32.
However, you cannot do:
public enum MyEnum : Int32
VALUE1 = 0,
Error: "Error 1 Type byte, sbyte, short, ushort, int, uint, long, or ulong expected"
This is a known bug related to the compiler parser that expects keywords, but not types (System.Int32 is a .NET ValueType, and "int" is just a registered keyword/type alias). Microsoft closed it with the remark: won't fix, reason: too much work to do for a very small benefit.

Parsing values from String Data
The .NET data types provide the ability to parse their type from string data. Example:
tmpBool = bool.Parse("True");
tmpInt = int.Parse("333");
There is also the method TryParse that, in comparison with Parse, does not throw an Exception, and has additional parameters to specify. Also, TryParse returns a bool indicating that the parsing failed or succeeded.
Parse if you don't care about it throwing exceptions, and you want to know why the parsing failed.
TryParse if you don't care why it failed and want no Exceptions.

System.DateTime and System.TimeSpan
DateTime is a type used to represent date and time, and TimeSpan allows operations on time. The example below gets the current time, and adds to it 24 hours.
DateTime dT = DateTime.Now;
System.TimeSpan tS = new TimeSpan(24, 0, 0);

Defines BigInteger and Complex types. These types were introduced with .NET Framework 4.0, and not available for prior versions. If you need a functionality similar to BigInteger, you may use a very good implementation by Chew Keong TAN:
BigInteger is not constrained to numerical limits, while Complex is used to model mathematically complex data.
Normally you construct a BigInteger instance from a numerical representation of the big number, or from another BigInteger, because otherwise it will be converted to the most representative type of the value you give as input, and an overflow might happen.

Working with Strings
Other that the fact that there are many methods that let you manipulate Strings in C#, the following facts are worth mentioning:
  1. Concatenating strings can be done using String.Concat, or simply str1 + str2 + ... + strN. But, for large N (>20), each concatenation does allocate new memory, and thus can cost much more than StringBuilder. Let's say that StringBuilder is used to concatenate unknown amount of data, and usually in a loop. StringBuilder allocates an initial buffer of 16 if none specified. The initial buffer is automatically increased if needed, by copying its data to a new instance. However, don't go too much into the optimization process, as it is not so significant, for sure in an average application you have many other problems that are more important. As codinghorror states:
    1: Simple Concatenation 606 ms
    2: String.Format 665 ms
    3: string.Concat 587 ms
    4: String.Replace 979 ms
    5: StringBuilder 588 ms
  2. If you want to disable processing of a literal's escape characters(\',\”,\\,\a,\n,\r,\t), you can precede it with the @ symbol. This is called a verbatim string.
  3. The strings are immutable, i.e. once assigned, it cannot be changed. Any changes are applied to new strings allocated on the heap.
Narrowing and Widening Data Type Conversions (Downward cast and Upward cast)
The value of a short can be assigned without loss of data to int, and thus the explicit cast is not required. However, the value of the int cannot be safely cast to short, so an explicit cast is required, otherwise the compiler gives an error. The code below is correct:
short sh1 = 100;
int i1 = 320000, i2 = 0;
i2 = sh1;
sh1 = (short)i1;
When using an explicit cast, the overflow occurs without error. .Net runtime by default ignores arithmetic overflow/underflow cases.

Checked keyword
This keyword allows you to instruct the compiler to generate an exception if an overflow or an underflow occurred.
byte b1 = 77, b2 = 100, b4 = 78;
// Overflow
byte b3 = checked((byte)(b1+b2));
// Underflow
b3 = (byte)(b1 - b4);
Project-wide checking of overflow/underflow cases, under Project/Properties/Build/Advanced

Unchecked keyword
This keyword allows you to override the project-wide checked setting if you want to allow the overflow to occur
b3 = (byte)(b1 - b4);

The var keyword
The var keyword allows you to declare implicitly typed local variables. The type is inferred automatically by the compiler. The keyword can be used only to declare local variables in methods or properties, and must have an initial assigned value. It cannot be declared for class variables or as a return type, and null cannot be assigned initially.
var myImplVar = "strTest";
The implicitly declared variables are useful when working with LINQ, when the return type is based on the formulated query.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.