I'm going through terrific "Essentials C# 4.0" - Mark Michaelis.
DATA TYPE
Float vs Double vs Decimal ?
Float has only 7 digit precision...
...
float floatSource = 1234.5678F;
double doubleSource = 1234.5678D;
decimal decimalSource = 1234.5678M;
decimal float2decimal = (decimal)floatSource;
decimal double2decimal = (decimal)doubleSource;
Console.WriteLine(float2decimal==decimalSource);
Console.WriteLine(double2decimal == decimalSource);
Console.ReadLine();
...
This results in:
false
true
Double has 15 digit precision but in business apps you can sometimes reach that limit too.
- Further good reading on subject :
Unexpected Inequality with Floating-Point Types
multiplying, dividing and casting between float and double results in Not equal results.
page 90
- Dividing with 0 and overflowing max is allowed with double / float and results with special NaN and Infinity
Rule of a thumb: For business apps use only DECIMAL type for storing money data.
Overflowing an integer value
Unless used with special checked block numerical type will overflow:
// int.MaxValue equals 2147483647
intn = int.MaxValue;
n = n + 1 ;
System.Console.WriteLine(n)
;results in : -2147483.
int result = myAge++; // Not thread safe
//Correct thread safe way
long b=0;
long i = System.Threading.Interlocked.Increment(ref b);
198 page
Because the property name is FirstName, the field name changed from
earlier listings to _FirstName. Other common naming conventions for
the private field that backs a property are _firstNameand m_FirstName
Regardless of which naming pattern you use for private fields, the coding standard for public fields and properties is Pascal case. Therefore, public properties should use the LastName and FirstName type patterns.
Similarly, if no encapsulating property is created around a public field,
Pascal case should be used for the field.
Prein(de)cremental and postin(de)cremental operands are NOT thread safe
int result = myAge++; // Not thread safe
//Correct thread safe way
long b=0;
long i = System.Threading.Interlocked.Increment(ref b);
FLOW CONTROL
I didn't know for this :case "Candies":
Console.WriteLine("I love all candies");
goto default;
case "Icecream":
Console.WriteLine("Jummy ... icecream.");
goto case "Candies";
default : ...
To comment or not ?
158 pageAs part of the coding process, it is a best practice to continually
review your code and look for opportunities to refactor. This involves
looking for blocks of code that are difficult to understand at a glance and
moving them into a method with a name that clearly defines the code’s
behavior. This practice is often preferred over commenting a block of
code, because the method name serves to describe what the implementation does.
Don't use exceptions as validation rules!
198 page
Exceptions are designed specifically for tracking exceptional, unexpected, and potentially fatal situations.
Using them for an unattended purpose such as expected situations will
cause your code to be hard to read, understand, and maintain.
Additionally, (as with most languages) C# incurs a slight performance
hit when throwing an exception—taking microseconds compared to the
nanoseconds most operations take. This delay is generally not noticeable
in human time—except when the exception goes unhandled. For example,
when executing Listing 4.19 and entering an invalid age the exception is
unhandled and there is a noticeable delay while the runtime searches the
environment to see whether there is a debugger to load. Fortunately, slow
performance when a program is shutting down isn’t generally a factor to
be concerned with.
Naming convention - field vs property -> field should have _ to make distinction
Because the property name is FirstName, the field name changed from
earlier listings to _FirstName. Other common naming conventions for
the private field that backs a property are _firstNameand m_FirstName
Regardless of which naming pattern you use for private fields, the coding standard for public fields and properties is Pascal case. Therefore, public properties should use the LastName and FirstName type patterns.
Similarly, if no encapsulating property is created around a public field,
Pascal case should be used for the field.
// FirstName property
public string FirstName
{
get
{
return _FirstName;
}
set
{
_FirstName = value;
}
}
private string _FirstName;
Single property can have different access modifiers for setter and getter
// Id property declaration
public stringId
{
get
{
return_Id;
}
// Providing an access modifier is in C# 2.0
// and higher only
private set
{
_Id = value;
}
}
private string_Id;
Use Automated property in combination with access modifiers for short and consistent use of properties
Unless there is some specific logic needed use consistently automated properties.
public static int First { get; set; }If it is required to allow only private setting of property use this:
public static int First { get; private set; }
Don't mix field initialization in declaration and in constructor
Developers should take care when using both assignment at declaration time and assignment within constructors. Assignments within the
constructor will occur after any assignments are made when a field is
declared (such as string Salary = "Not enough"in Listing 5.5). Therefore, assignment within a constructor will override any value assigned at
declaration time. This subtlety can lead to a misinterpretation of the code
by a casual reader whereby he assumes the value after instantiation is
assigned at declaration time. Therefore, it is worth considering a coding
style that does not mix both declaration assignment and constructor
assignment within the same class.
Constructor chaining
public Employee(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
}
public Employee(int id, string firstName, string lastName ) : this(firstName, lastName)
{
Id = id;
}
Static Constructors
In bellow code first will get executed declaration 42 then random generator.classEmployeeFavor Static Initialization during Declaration instead of static constructors because compiler injects special extra check to ensure that constructor initialization always wins over field initialization which can be expensive.
{
static Employee()
{
Random randomGenerator = new Random();
NextId = randomGenerator.Next(101, 999);
}
// ...
public static int NextId = 42;
// ...
}
Favor static properties instead of static fields
It is almost always better to use a static property rather than a public staticfield because public static fields are callable from anywhere whereas a
static property offers at least some level of encapsulation.
Use extension methods wisely
Note that specializing a type via inheritance is preferable to using an extension method. Extension methods do not provide a clean versioning mechanism since the addition of a
matching signature to the extended type will take precedence over the
extension method without warning of the change. The subtlety of this is
more pronounced for extended classes whose source code you don’t control. Another minor point is that, although development IDEs support IntelliSense for extension methods, it is not obvious that a method is an extension method by simply reading through the calling code. In general,
use extension methods sparingly.
public class Dummy
{
public int Id { get; set; }
public int BuildUrl()
{
return this.Id * 2;
}
}
static class Extensions
{
public static int BuildUrl(this Dummy value)
{
return value.Id;
}
}
Extension method will be ignored!
One of the features included with extension methods is the fact that they
too are inherited. If we extend a base class such as PdaItem, all the extension methods will also be available in the derived classes. However, as
with all extension methods, priority is given to instance methods. If a compatible signature appears anywhere within the inheritance chain, this will take precedence over an extension method.
Partial methods
// File: Person.Designer.cs public partial class PersonIt is important to note that a partial method must return void.Similarly, outparameters are not allowed on partial methods.
{
partial void OnLastNameChanging(stringvalue);
partial void OnFirstNameChanging(stringvalue);
...
// File: Person.cs partial class Person
{
partial void OnLastNameChanging(stringvalue)
{
if(value == null)
{
...
Custom explicit operator
public class Dvd:Storage...
{
public string Name { get; set; }
public static explicit operator CdRom(Dvd dvd)
{
CdRom result = new CdRom();
...
return result;
}
}
CdRom cdromFromDvd = (CdRom)dvd;
Class inheritance with "as" and "is"
By using the as operator, you are able to avoid additional try/catchhandling code if the conversion is invalid, because the as operator provides
a way to attempt a cast without throwing an exception if the cast
fails.
One advantage of the is operator over the as operator is that the latter
cannot successfully determine the underlying type. The latter potentially
casts up or down an inheritance chain, as well as across to types supporting
the cast operator. Therefore, unlike the as operator, the is operator can
determine the underlying type.
The as operator is like a cast operation. However, if the conversion is not possible, as returns null instead of raising an exception.
Base baseType = derivedType as Base;
if (derivedType is Base) ...Note that the as operator only performs reference conversions and boxing conversions. The as operator cannot perform other conversions, such as user-defined conversions, which should instead be performed by using cast expressions.
Mimicing multiple inheritance with single inheritance & private members
public classPdaItem
{}
public classPerson
{}
public classContact : PdaItem
{
private Person InternalPerson {get; set; }
public string FirstName
{
get{ return InternalPerson.FirstName; }
set{ InternalPerson.FirstName = value; }
}
Method marked override always has precedence over base virtual method
public class Storage
{
public virtual string SerialNum()
{
return "Storage";
}
public class CdRom : Storage
{
public override string SerialNum()
{
return "CdRom";
}
CdRom cdrom = new CdRom();
Storage storage = cdrom;
Console.WriteLine(storage.SerialNum());
In order to instruct compiler to call Storage.SerialNum() change this:
public override string SerialNum() --> public new string SerialNum()
The rule is that whenever the runtime encounters a virtual method, it calls the most
derived and overriding implementation of the virtual member. In creating a class, programmers should be careful when choosing to allow overriding a method, since they cannot control the derived implementation.
Accessing members of parent type using base keyword
public class Storage
{
public string BaseVersion { get; set; }
...
public class CdRom : Storage
{
public void Eject()
{
string StorageBaseVersion = base.BaseVersion;
}
Abstract classes
public abstract class Storage ...
{
public abstract string GetUID();
...
public class Dvd : Storage ...
{
public override string GetUID();
Abstract vs interfaces
The key point, therefore, is that base classes let you share implementation along with the member
signatures, whereas interfaces allow you to share the member signatures without the implementation.
Explicit vs Implicit interfaces
Example of two interfaces. Idea is to version changes in CalculateSerialNum() functionality.
Bellow example demonstrates how can we introduce changes in functionality for method with signature CalculateSerialNum() without changing method signature.
Using explicit interface members we are allowed to freely add unlimited versions of same method signature CalculateSerialNum() just by introducing new interfaces.
interface IStorageV2
{
string CalculateSerialNum();
}
interface IStorage
{
void Save();
void Load();
string CalculateSerialNum();
}
public class Dvd : IStorage, IStorageV2
{
public void Save()
{
throw new NotImplementedException();
}
public void Load()
{
throw new NotImplementedException();
}
// Implicit interface implementation
public string CalculateSerialNum()
{
return "Version 1";
}
// Explicit interface implementation
string IStorageV2.CalculateSerialNum()
{
return "Version 2";
}
}
Dvd dvd = new Dvd();
//original initial code
Console.WriteLine( dvd.CalculateSerialNum());
//new functionality without touching method signature
Console.WriteLine(((IStorageV2)dvd).CalculateSerialNum());
Explicit interface implementation is a technique for enabling the separation of mechanism concerns from model concerns.
In general, it is preferable to limit the public surface area of a class to be “all model” with as little extraneous mechanism as possible.
Since changing an implementation from implicit to explicit results in a
version-breaking change, it is better to err on the side of defining interfaces
explicitly, allowing them to be changed to implicit later on. Furthermore,
since the decision between implicit and explicit does not have to be consistent
across all interface members, defining some methods as explicit and
others as implicit is fully supported.
Interfaces can inherit single or multiple interfaces
Although inheritance is the correct term, conceptually it is more accurate to realize that an interface represents a contract; and one contract is allowed to specify that the provisions of another contract must also be followed.
Interfaces can be extended with extension method
public static class Extensions
{
//Extending interface with extension method
public static bool IsBig(this IStorage value)
Observe that "value" is not standard param. It is missing when using method. Purpose is to optionally use value of provided instance in method logic.
Dvd dvd = new Dvd().IsBig();
Extension method can extend collection of target class or interface
Extending collection of class:public static class ExtensionsExtending collection of interface:
{
public static bool MyExists(this IEnumerable<Dvd> dvds, Dvd dvd)
{
return dvds.Any<Dvd>(d => d.Equals(dvd));
...
Dvd dvd = new Dvd();
List<Dvd> dvds = new List<Dvd>();
bool isOk = dvds.MyExists(dvd);
public static class Extensions...
{
public static bool MyExists(this IEnumerable<IStorage> storages, IStorage storage)
{
foreach (var item in storages)
{
if (item.Equals(storage)) return true;
}
return false;
}
Dvd dvd = new Dvd();
List<Dvd> dvds = new List<Dvd>();
dvds.MyExists(dvd);
List<CdRom> cdroms = new List<CdRom>();
CdRom cdRom = new CdRom();
cdroms.MyExists(cdRom);
Versioning with interfaces
Changing interfaces during the development phase is obviously acceptable, although perhaps laborious if implemented extensively. However, once an interface is released, it should not be changed. Instead, asecond interface should be created, possibly deriving from the original interface.
Abstract classes vs interfaces
Interfaces
Cannot be instantiated.
Although no default implementation
can appear, classes implementing
interfaces can continue to derive from
one another.
All members are automatically
virtual and cannot include any
implementation.
Cannot store any data. Fields can be
specified only on the deriving
classes. The workaround for this is
to define properties, but without
implementation.
Extending interfaces with additional
members breaks the version
compatibility.
Implementation of all members of the
interface occurs in the base class. It is
not possible to implement only some
members within the implementing
class.
Abstract classes
Cannot be instantiated independentlyfrom their derived classes.
Abstract class constructors are called
only by their derived classes.
Define abstract member signatures
that base classes must implement.
Are more extensible than interfaces,
without breaking any version compatibility.
With abstract classes, it is
possible to add additional nonabstract
members that all derived
classes can inherit.
Can include data stored in fields.
Allow for (virtual) members that
have implementation and, therefore,
provide a default implementation of
a member to the deriving class.
Deriving from an abstract class uses
up a subclass’s one and only base
class option.
Value vs Reference types
The amount of memory that is required for the value type is fixed atcompile time and will not change at runtime. This fixed size allows value
types to be stored in the area of memory known as the stack.
The memory area of the data a reference type points to is the heap.
Besides string and object, all the C# primitive types are value types.
Value types
All value types are sealed. In addition, all value types derive from System.ValueType. This means that the inheritance chain for structs is always from object to ValueType to the struct.
As with classes, you can override the virtual members of System.Object. The rules for overriding are virtually the same as with reference types. However, one difference is that with value types, the default implementation for GetHashCode() is to forward the call to the first non-null field within the struct.
Also, Equals() makes significant use of reflection. This leads to the conclusion that if a value type is frequently used inside collections, especially dictionary-type collections that use hash codes, the value type should include overrides for both Equals() and GetHashCode().
Boxing
int dummy = 1;Process:
object dummyBoxed = (object)dummy;
1.First, memory is allocated on the heap that will contain the value
type’s data and a little overhead (a SyncBlockIndex and method
table pointer).
2. Next, a memory copy occurs from the value type’s data on the stack,
into the allocated location on the heap.
3. Finally, the object or interface reference is updated to point at the
location on the heap.
Don't use boxing and unboxing value types without variables
Don't change value type value during boxing/unboxing in single statement. Use temp variables to first store boxed or unboxed value on stack or heap. Then apply change to value.Bellow is example of statements that failed expected behavior since change of value type is done "on fly" without first assigning it to appropriate variables.
struct Angle : IAngleOutput: 25, 25, 25, 26
{
// ...
// NOTE: This makes Angle mutable, against the general
// guideline
public void MoveTo(int hours, int minutes, int seconds)
{
_Hours = hours;
_Minutes = minutes;
_Seconds = seconds;
}
}
interface IAngle
{
void MoveTo(int hours, int minutes, int seconds);
}
// ...
Angle angle = new Angle(25, 58, 23);
object objectAngle = angle; // Box
Console.Write( ((Angle)objectAngle).Hours);
// Unbox and discard
((Angle)objectAngle).MoveTo(26, 58, 23);
Console.Write( ((Angle)objectAngle).Hours);
// Box, modify, and discard
((IAngle)angle).MoveTo(26, 58, 23);
Console.Write(", " + ((Angle)angle).Hours);
// Modify heap directly
((IAngle)objectAngle).MoveTo(26, 58, 23);
Console.WriteLine(", " + ((Angle)objectAngle).Hours);
// ...