Advanced Effective C# - Part II

Topics

Generics

1. Use Generic Replacements of 1.x Framework API Classes

When you use System.Object as a parameter or return type, you have the potential to substitute the wrong type which can cause run time errors. Also the use of System.Object means that value types will have to boxed and unboxed every time you coerce between the value type and System.Object. This may have a significant impact on performance (applies only with value types) The use of generics enforces correctness and improves performance.
 

   20     class Item1

   21     {

   22         /// <summary>

   23         ///  With generics, you can create simple functions to visit every item

   24         ///  in a collection

   25         /// </summary>

   26         public void TestGenerics1()

   27         {

   28             List<int> lst = new List<int>() { 1, 2, 3, 4 };

   29             Action<int> delPrint = Print;

   30             EnumerateAll(lst, delPrint);

   31 

   32             // could also call EnumerateAll using the following syntax

   33             EnumerateAll(lst, Print);

   34         }

   35         private void EnumerateAll<T>(IEnumerable<T> collection, Action<T> action)

   36         {

   37             foreach (T obj in collection)

   38                 action(obj);

   39         }

   40 

   41         private void Print<T>(T obj)

   42         {

   43             Trace.WriteLine("Item is: ", obj.ToString());

   44         }

   45 

   46         /// <summary>

   47         /// To sort an array of objects that does not implement IComparable<T>,

   48         /// you can supply a delegate that matches System.Comparison<T> delegate

   49         /// </summary>

   50         public void TestGenerics2()

   51         {

   52             List<string> lst = new List<string> { "B2", "B1", "A2", "A1" };

   53             lst.Sort(MyStringComparison);

   54             Trace.WriteLine(lst.ToString());

   55         }

   56 

   57         private int MyStringComparison<T>(T x, T y)

   58         {

   59             string s1 = x as string;

   60             string s2 = y as string;

   61 

   62             if ((x == null) || (y == null)) return -1;

   63 

   64             if (s1[0] < s2[0])

   65                 return -1;

   66             if (s1[0] > s2[0])

   67                 return 1;

   68             else

   69             {

   70                 if (s1[1] < s2[1])

   71                     return -1;

   72                 if (s1[1] > s2[1])

   73                     return 1;

   74                 else

   75                     return 0;

   76             }

   77         }

   78 

   79 

   80         /// <summary>

   81         /// System.Convertr<T,S> generic delegate converts one input object into a

   82         /// corresponding output:

   83         ///    public delegate TOutput Converter<TInput, TOutput>(TInput input)

   84         ///   

   85         /// Converter is therefore a delegate that takes an input of type TInput

   86         /// and returns an object of type TOutput

   87         /// </summary>

   88         public void TestGenerics3()

   89         {

   90             // Create an array of PointF points (note use of C# 3.0 Object Initializers)

   91             PointF[] ptsFloat = new PointF[] { new PointF{X=1.1F, Y=1.1F},

   92                                             new PointF{X=2.1F, Y=2.1F},

   93                                             new PointF{X=3.1F, Y=3.1F}};

   94 

   95             // Now convert to a list of Point points

   96             IEnumerable<Point> ptsInt = Transform<PointF, Point>(ptsFloat, PointFToPoint);

   97 

   98         }

   99 

  100         private Point PointFToPoint(PointF srcPoint)

  101         {

  102             return new Point((int)srcPoint.X, (int)srcPoint.Y);

  103         }

  104 

  105         /// <summary>

  106         ///  Transform has two type parameters: TInput and TOutput, which represent the input

  107         ///  and output types for the transform

  108         /// </summary>

  109         private IEnumerable<TOutput> Transform<TInput, TOutput>(IEnumerable<TInput> collSrc, Converter<TInput, TOutput> converter)

  110         {

  111 

  112             List<TOutput> lst = new List<TOutput>();

  113             foreach (TInput item in collSrc)

  114                 lst.Add(converter(item));

  115 

  116             return lst;

  117         }

  118 

  119         /// <summary>

  120         /// In .NET 1.1, you had to create a class derived from EventArgs, then create

  121         /// the delegate definition to refer to the derived class, and then create an event

  122         /// definition to match the delegage:

  123         ///    public MyEventArgs : EventArgs { ... }

  124         ///    public delegate void MyEventHandler(object sender, MyEventArgs args);

  125         ///    public event MyEventHandler MyEvent

  126         ///   

  127         /// .NET 2.0 now includes a generic definition for the event handler:

  128         ///    public delegate void EventHandler<TEventArgs>(Object sender, TEventArgs e) where TEventArgs : EventArgs

  129         ///   

  130         /// Now declaring MyEvent looks like:

  131         ///    public event EventHandler<MyEventArgs> MyEvent;

  132         /// </summary>

  133         public void TestGenerics4()

  134         {

  135             this.MyEvent += new EventHandler<MyEventArgs>(Item1_MyEvent);

  136 

  137             MyEvent(this, new MyEventArgs("hello from generic event handler"));

  138         }

  139 

  140 

  141         public event EventHandler<MyEventArgs> MyEvent;

  142         public class MyEventArgs : EventArgs

  143         {

  144             private string msg;

  145 

  146             public MyEventArgs(string messageData)

  147             {

  148                 msg = messageData;

  149             }

  150             public string Message

  151             {

  152                 get { return msg; }

  153                 set { msg = value; }

  154             }

  155         }

  156 

  157         void Item1_MyEvent(object sender, Item1.MyEventArgs e)

  158         {

  159             Trace.WriteLine(e.Message);

  160         }

  161     }

2. Define Constraints That Are Minimal and Sufficient

First recall some generics terminology. Given Stack<T> and Stack<int>, the following terminology is used

The whole point of creating a generic type is to create a type definition that can be used efficiently in as many scenarios as possible. You need to balance the safety of specifying 'constraints' against the extra work required by programmers to deal with every extra constraint. Strive for the minimal set of assumptions, but specify all assumptions as constraints.

If you do not specify any constraints, you must perform more checks at runtime. Constraints enable the compiler to expect capabilities in a type parameter T beyond those in the public interface in System.Object. Without any guidance from the developer, the compiler only assumes that the generic type exposed only the methods of System.Object. The compiler will emit errors on anything not defined in System.Object. This even includes fundamental operations such as new T() which is hidden if you define a constructor that has parameters. Therefore, use constraints to communicate to the compiler and users any assumptions you've made about the generic type.

Although you need to specify the necessary constraints, you also need to minimize the number of constraints you place on your generic type parameters. One of the most common ways is to ensure that your generic types (for example, Stack<T>) do not require functionalities that they do not use:

class Item2

{

    /// <summary>

    /// The alternative to not using contraints is to perform lots of casting and runtime

    /// checks. AreEqual<T> is a generic method that tests if two objects are equal using

    /// IComparable<T>. Becasue AreEqual<T> does not declare any contraints on T, it must

    /// therefore check for the presence of IComparable<T>

    /// Not specifying necessary constraints means that your methods/classes could easily

    /// be misused, producing exceptions or runtime errors when client programmers guess

    /// wrong

    /// </summary>

    public bool AreEqual<T>(T lhs, T rhs)       //lhs, rhs: left-hand side and right-hand side

    {

        // If either parameter is null, return false

        if ((lhs == null) || (rhs == null)) return false;

 

        // Check that lhs implements IComparable<T>

        IComparable<T> ILhs = lhs as IComparable<T>;

        if (ILhs != null)

            return (ILhs.CompareTo(rhs) == 0);

        else

            throw new InvalidOperationException("lhs does not implement IComparable<T>");

    }

 

    /// <summary>

    /// The equivalent method is much simpler if you specify that T must implement IComparable<T>

    /// This method trades run time errors (see exception code in AreEqual) with compile-time

    /// errors: compiler generates errors if lhs or rhs does not derive from IComparable<T>

    ///

    /// </summary>

    public bool AreEqualWithConstraints<T>(T lhs, T rhs) where T : IComparable<T>

    {

        // No need to perform runtime checks

        return (lhs.CompareTo(rhs) == 0);

    }

 

    /// <summary>

    /// If AreEqual2<T> is defined in a generic type (say, Stack<T>) that declares the

    /// IEquatable<T> constraint, it will call IEquatable<T>.Equals. Otherwise, the C#

    /// compiler cannot assume that IEquatable<T> is present and will instead call

    /// System.Object.Equals

    ///

    /// This example illustrates the basic difference between C# generic and C++ Templates

    /// In C#, the compiler must generate IL using only the information specified in constraints.

    /// Even if the type specified for a specific instantiation has a better method (ie,

    /// IEquatable<T>.Equals), it will not be used unless it was specified when the generic type

    /// (Stack<T>) was compiled.

    ///

    /// So, must every using AreEqual2<T> implement IEquatable<T>? The answer is no. Rather than

    /// adding a IEquatable<T> constraint on AreEqual2<T>, in the function body check for existence

    /// of IEquatable<T>, and if not present, transparently downgrade to the less preferred

    /// Object.Equals method. See AreEqual3<T>

    /// </summary>

    public bool AreEqual2<T>(T lhs, T rhs)

    {

        return lhs.Equals(rhs);

    }

 

    /// <summary>

    ///

    /// </summary>

    public bool AreEqual3<T>(T lhs, T rhs)

    {

        // If either parameter is null, return false

        if ((lhs == null) || (rhs == null)) return false;

 

        // Check that lhs implements IComparable<T>

        IEquatable<T> ILhs = lhs as IEquatable<T>;

        if (ILhs != null)

            return (ILhs.Equals(rhs));

        else

            return lhs.Equals( rhs );

 

    }

 

    /// <summary>

    /// Recall that the new() constraint indicates to the compiler that a generic type parameter

    /// (T in Stack<T>) supports a public default constructor (constructor with no params). In some

    /// cases you can replace the new() constraint by replacing 'new' calls with default(), which is

    /// an operator that initialzes a variable to its default value (0s for value types and null for

    /// reference types).

    ///

    /// The following method wraps a factory method (FactoryFunc delegate) to create an object

    /// of type T. If the factory method fails to create an object of type T, it returns the value

    /// returned by the default constructor. This method must therefore specify the new() constraint.

    /// Also because of the test for null, the behavior is different for value types. Value types

    /// cannot be null and therefore the caluse under the if statement will never be executed (the

    /// JIT compiler will remove the null test if T is a value type). Therefore, be careful when

    /// adding new() constraint as it creates assumptions about how an object will be constructed.

    /// </summary>

    public delegate T FactoryFunc<T>();

    public T Factory<T>( FactoryFunc<T> MakeNewT) where T : new ()

    {

        T val = MakeNewT();

        if (val == null)

            return new T();        // replace with default(T) and remove the 'new()' constraint

        else

            return val;

    }

}

 

// Test class that implements IComparable<T>

class Order : IComparable<Order>

{

    public int nOrderID;

 

    public Order(int id) { nOrderID = id; }

    #region IComparable<Order> Members

    public int CompareTo(Order other)

    {

        if ((this == null) && (other == null)) return 0;

        if ((this == null) && (other != null)) return -1;

        if ((this != null) && (other == null)) return 1;

        return nOrderID.CompareTo(other.nOrderID);

    }

    #endregion

}

 

// Test class that does not implement IComparable<T>

class Customer

{

    public int nCustomerID;

 

    public Customer(int id) { nCustomerID = id; }

}

3. Specialize Generic Algorithms Using Runtime Type Checking

Given Stack<T>, you can supply different generic type parameter T to create different types but with similar functionality (Stack<int>, Stack<Order>, Stack<Student>, etc.) However, generics may limit you by not being able to take advantage of a more specific superior algorithm. This is addressed by recognizing that the algorithm can be more efficient when a generic type parameter T has specific capabilities, i.e., implements a specific interface, and then utilize that capability to implement a more efficient and superior algorithm.

class Item3

{

    public void TestReverseEnumerable()

    {

        List<int> lst = new List<int>();

        lst.Add(1);

        lst.Add(2);

        lst.Add(3);

        ReverseEnumerable<int> re = new ReverseEnumerable<int>(lst);

        foreach (int n in re)

            Trace.WriteLine( n );

 

    }

}

 

/// <summary>

/// Helper class

/// Recall that IEnumerable<T> exposes an enumerator which supports a simple iteration

/// over a collection of type T

///

/// ReverseEnumerable constructor takes an input parameter that supports IEnumerable<T>.

/// IEnumerable<T> does not support random access

/// </summary>

class ReverseEnumerable<T> : IEnumerable<T>

{

    private IList<T> originalSequence;

    IEnumerable<T> sourceSequence;

 

    // Constructor

    public ReverseEnumerable(IEnumerable<T> sequence)

    {

        sourceSequence = sequence;

 

        // Make use of the fact that many types that implement IEnumerable<T> also implement

        // IList<T>. This improves the efficiency of the code by not having to create an unnecessary

        // copy of sequence. IList<T> enables a more efficient algorithm than does IEnumerable<T>

        // and we have not forced consumers of this class to provide more functionality

        // If 'sequence' does not implement IList<T>, 'originalSequence' is null, and this works

        // fine as it gets initialized in GetEnumerator() function.

        originalSequence = sequence as IList<T>;

    }

 

    #region IEnumerable<T> Members

    public IEnumerator<T> GetEnumerator()

    {

        // Create a copy of the source sequence so it can be reversed

        if (originalSequence == null)

            originalSequence = new List<T>(sourceSequence);

 

        // Return an object that implements IEnumerator<T>

        return new ReverseEnumerator<T>(originalSequence);                           

    }

 

    #endregion

 

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()

    {

        return this.GetEnumerator();

    }

    #endregion

}

 

/// <summary>

/// Helper class

/// Recall that IEnumerator<T> supports a simple iteration over a collection of type T

/// </summary>

class ReverseEnumerator<T> : IEnumerator<T>

{

    private int nCurrentIndex;

    private IList<T> collection;

 

    // Constructor

    public ReverseEnumerator(IList<T> source)

    {

        collection = source;

        nCurrentIndex = source.Count;       // nCurrenIndex starts from the end

    }

 

    #region IEnumerator<T> Members

    public T Current

    {

        get { return collection[nCurrentIndex]; }

    }

    #endregion

 

    #region IDisposable Members

    public void Dispose()

    {

        // No implementation is needed as there are no unmanaged resources

    }

    #endregion

 

    #region IEnumerator Members

    object System.Collections.IEnumerator.Current

    {

        get { return this.Current;  }

    }

 

    public bool MoveNext()

    {

        return (--nCurrentIndex >= 0);

    }

 

    public void Reset()

    {

        nCurrentIndex = collection.Count;

    }

    #endregion

}

4. Use Generics to Force Compile-Time Type Inference

Generics allow you to minimize the amount of code required to create and support a given pattern. For example, consider the List<T>.Find( Predicate<T> match) function that finds the first element that meets a specific condition. The List class also contains similar methods for FindAll, TrueForAll, ForEach, and others. The collection class now contains a common algorithm to enumerate all nodes in a collection; the collection class provides a generic method to visit each element and the user need only supply the logic that is to be applied to each element in the collection. You examine all the elements for a variety of reasons: searching for something, testing the values of the elements,  or transforming the values of the elements.
 
In the same way, you can implement many design patterns by defining the proper delegates or events in the form of predicates. These generic implementations can be reused whenever you need to implement the same pattern. In other words, you may find that you create algorithms that use the type of an object to implement the algorithm. In that case, you can often create a single generic version of the algorithm by abstracting away the type parameters into generic parameters. Then the compiler can create the specific versions for you

/// <summary>

/// This is a helper class that illustrates a pattern for serialization/deserialization

/// This is a non-generic version that can serialize any arbitrary type

///

/// XmlPersistenceManager works but its use requires a type be specified as it (the type)

/// cannot be inferred. There is also the issue of type safety: every time you call

/// LoadFromFile() you must cast or convert the returned object. There is also a hidden

/// inefficiency: every call to one of the class methods create a new XmlSerializer which

/// can indirectly create lots of temporary object that are not needed.

/// </summary>

internal static class XmlPersistenceManager

{

    private static object LoadFromFile(Type typeToLoad, string strFilePath)

    {

        // If file does not exist, return the defautl value for object (i.e., null)

        if (!File.Exists(strFilePath))

            return default(object);

 

        // Otherwise, load stream from file and convert to an object

        using (TextReader tr = new StreamReader(strFilePath))

        {

            XmlSerializer serializer = new XmlSerializer(typeToLoad);

            return serializer.Deserialize(tr);

        }

    }

 

    private static void SaveToFile(string strFilePath, object ob)

    {

        Type typeToSave = ob.GetType();

        using (TextWriter tw = new StreamWriter(strFilePath))

        {

            XmlSerializer serializer = new XmlSerializer(typeToSave);

            serializer.Serialize(tw, ob);

        }

    }

}

 

/// <summary>

/// The following is a generic version of XmlPersistenceManager that is type-safe

/// and efficient

/// </summary>

internal static class GenericXmlPersistenceManager<T>

{

    // Cache the serializer once it is created

    private static XmlSerializer serializer = null;

    private static T LoadFromFile(string strFilePath)

    {

        // Create the XmlSerializer once, and cache it for the rest of time as each

        // XmlSerializer is tied to a specific Type class

        if (serializer == null)

            serializer = new XmlSerializer(typeof(T));

 

        // If file does not exist, return the defautl value for object (i.e., null)

        if (!File.Exists(strFilePath))

            return default(T);

 

        // Otherwise, load stream from file and convert to an object

        using (TextReader tr = new StreamReader(strFilePath))

        {               

            return (T)serializer.Deserialize(tr);

        }

    }

 

    private static void SaveToFile(string strFilePath, T ob)

    {

        // Create the XmlSerializer once, and cache it for the rest of time as each

        // XmlSerializer is tied to a specific Type class

        if (serializer == null)

            serializer = new XmlSerializer(typeof(T));

 

        using (TextWriter tw = new StreamWriter(strFilePath, false))

        {               

            serializer.Serialize(tw, ob);

        }

    }

}

5. Ensure That Generic Classes Support Disposable Type Parameters

Constraints on generic classes imply two things:

  1. Run-time errors are converted to compile-time errors.

  2. Specify requirements of the generic type parameter (T in Stack<T>)

In most cases, you don't care what capabilities a generic type parameter T has beyond those your generic type (Stack<T>) expects and uses. In the special case of a generic type parameter that implements IDisposable, you need to be aware of resource leaks. The recommended approaches are:

Therefore, if you create instances of any of the types described by your generic class's type parameters, you must consider that those types may implement IDisposable. You must code defensively and ensure that you don't leak resources when those objects go out of scope. Sometimes you can do that by refactoring the code so that it does not create those instances. At other times the best design is to create and use local variables, writing the code to dispose of them if needed.

public class Item5

{

    internal void TestLeakableGenericClass()

    {

        // Note that 'OrderEngine_v1' is responsible for creating an instance

        // of BookORder

        OrderEngine_v1<BookOrder> v1 = new OrderEngine_v1<BookOrder>();

        v1.ProcessOrder_CanCauseLeak("test");

        v1.ProcessOrder_NoLeak("test");

 

        // Note that we are now responsible for creating and managing BookOrder

        // object

        BookOrder bo = new BookOrder();

        using (bo as IDisposable)

        {

            OrderEngine_v2<BookOrder> v2 = new OrderEngine_v2<BookOrder>(bo);

            v2.ProcessOrder("test");

 

        }   // bo.Dispose() called her, IF bo implements IDisposable

    }

}

 

/// <summary>

/// Helper class to illustrate possible resource leaks when using generic type parameters

/// In method ProcessOrder_CanCauseLeak, we create and use an instance of the generic

/// type parameter (T). But what if T was a disposable type that required Dispose to be

/// explicitly called? You will introduce a resource leak if T implements IDisposable

/// </summary>

public class OrderEngine_v1<T> where T : IOrder, new()

{   

    /// <summary>

    /// Create an instance of T. What if T required Dispose to be called on it? You get

    /// a resource leak

    /// </summary>       

    public void ProcessOrder_CanCauseLeak(string name)

    {

        // Create an instance of T. Note that we own and control the instance

        T order = new T();

        order.CreateOrder(name);

    }

 

    /// <summary>

    /// To prevent the possibility of a resouce leak as in ProcessOrder_CanCauseLeak, in every

    /// case where you create a local variable of type T, you need to check whether T implements

    /// IDisposable, and, if so, dispose of it correctly

    /// </summary>

    public void ProcessOrder_NoLeak(string name)

    {

        // Create an instance of T. Note that we own and control the instance

        T order = new T();

 

        // Note that casting syntax inside using. The compiler creates a hidden local variable that

        // stores a reference to the order cast as an IDisposable. If T does not implement IDisposable,

        // then the value of this local variable is null. In those cases, the compiler does not call

        // Dispose(), because it checks against null before doing this extra work. However, in all cases

        // where T implements IDisposable, the compiler generates a call to the Dispose() method upon

        // exiting the using block.

        using (order as IDisposable)

        {

            order.CreateOrder(name);

        }

    }       

}

 

/// <summary>

/// In OrderEngine_v1, an instance of T was created as a local variable inside a function.

/// Things can get more complicated when the generic class needs to create and use an instance

/// of T as a member variable (see _order member variable below).

///

/// The recommended approach is to change the interface of the generic type so as to let the

/// user of the class be responsible for

///     1. Creating an instance of the generic type parameter (T), and

///     2. Calling Dispose on the generic-type-parameter instance

/// </summary>

public class OrderEngine_v2<T> where T : IOrder

{

    T _order = default(T);

 

    // Constructor

    public OrderEngine_v2(T order)

    {

        // We do not create the order. The user of the class create 'order' and passes it in

        // Contrast this to OrderEngine_v1 methods

        _order = order;

    }

 

    public void ProcessOrder(string name)

    {

        // No need to check for IDisposable. This responsibility has been moved to the user.

        _order.CreateOrder(name);

    }

}

 

public interface IOrder

{

    void CreateOrder(string strName);

}

 

// BookOrder is a type argument for OrderEngine_v1<T>

public class BookOrder : IOrder

{

    public string _strBookName;

 

    #region IOrder Members

    public void CreateOrder(string strName)

    {

        _strBookName = strName;

 

        // Other required steps ...

    }

    #endregion

}

 

// DVDOrder is a type argument for OrderEngine_v1<T>

public class DVDOrder : IOrder

{

    public string _strDVDName;

 

    #region IOrder Members

    public void CreateOrder(string strName)

    {

        _strDVDName = strName;

 

        // Other required steps ...

    }

    #endregion

}

6. Use Delegates to Define Method Constraints on Generic Type Parameters

Assume you have a generic class that needed an Add() method on T. You would create an IAdd<T> interface and you'd code against that interface. Every developer who wants to use your generic class would need to do more work: They'd need to create a class that implements IAdd<T>, define the methods needed for IAdd<T>, and then specify the closed generic class for your generic class definition. See DoNotUseCode() and DoNotUse namespaces in the code below. This is solved by specifying a delegate signature that matches the method your generic class needs to call. See UseThisCode and UseThis namespace.

Therefore, when it's unwieldy to use an interface to define a constraint (see DoNotUse namespace), you can define a method signature and a delegate type that suits your needs (see UseThis namespace).  Then you add an instance of that delegate to the list of the parameters of the generic method (Add method). The developers using your class can use a lambda expression to define that method, writing much less code, in a much clearer fashion. There's no extra code to support the syntax of interface-based constraints.

class Item6

{

    /// <summary>

    /// Incorrect approach to use an Add() method on T in a generic class

    /// </summary>

    public void DoNotUseCode()

    {

        DoNotUse.OrderEngine<DoNotUse.BookOrder> oe = new DoNotUse.OrderEngine<DoNotUse.BookOrder>();

        DoNotUse.BookOrder bo1 = new Samples.DoNotUse.BookOrder(10);

        DoNotUse.BookOrder bo2 = new Samples.DoNotUse.BookOrder(20);

        DoNotUse.BookOrder boSum = oe.AddOrder(bo1, bo2);           

    }

 

    /// <summary>

    /// Correct approach to use an Add() method on T in a generic class.

    /// </summary>

    public void UseThisCode()

    {

        UseThis.OrderEngine<UseThis.BookOrder> oe = new UseThis.OrderEngine<UseThis.BookOrder>();

        UseThis.BookOrder bo1 = new UseThis.BookOrder(1);

        UseThis.BookOrder bo2 = new UseThis.BookOrder(2);           

        UseThis.BookOrder sum = oe.AddOrder(bo1, bo2, delegate(UseThis.BookOrder o1, UseThis.BookOrder o2)

        {

            int nTotal = o1.nTotal + o2.nTotal;

            UseThis.BookOrder s = new Samples.UseThis.BookOrder(nTotal);

            return s;

        });

    }

 

    /// <summary>

    /// This method illustrates the use of delegate-based contracts to create algorithms that

    /// operate on sequences. In this example, Merge helper method enumerates both input sequences,

    /// and for each pair of items in the input sequence, it calls the merger delegate to return a

    /// new constructed TOutput object

    ///

    /// </summary>

    public void GenericMerge()

    {

        float[] dXValues = { 2, 4, 6, 8, 10 };

        float[] dYValues = { 1, 3, 5, 7, 9 };

 

        IEnumerable<PointF> Points = Merge(dXValues, dYValues, delegate(float x, float y)

        {

            return new PointF(x, y);

        });

    }

 

    private IEnumerable<TOutput> Merge<T1, T2, TOutput>(IEnumerable<T1> XValues, IEnumerable<T2> YValues, Func<T1, T2, TOutput> merger)

    {

        // Get enumerators to help traverse Xvalues and YValues arrays

        IEnumerator<T1> XEnumerator = XValues.GetEnumerator();

        IEnumerator<T2> YEnumerator = YValues.GetEnumerator();

 

        // Iterator over both X and Y enumerators

        while (XEnumerator.MoveNext() && YEnumerator.MoveNext())

        {

            yield return merger(XEnumerator.Current, YEnumerator.Current);

        }

    }

}

 

namespace DoNotUse

{

    // Created by class developer

    interface IAdd<T>

    {

        T Add(T other);

    }

 

    // Created by class developer

    class OrderEngine<T> where T : IAdd<T>

    {

        public T AddOrder(T order1, T order2)

        {

            T orderSum = order1.Add(order2);

            return orderSum;

        }

    }

 

    // Created by developer wishing to use OrderEngine<T>

    class BookOrder : IAdd<BookOrder>

    {

        public int nTotal = 0;

        public BookOrder(int tot) { nTotal = tot; }

        public BookOrder Add(BookOrder other)

        {

            int nSum = this.nTotal + other.nTotal;

            BookOrder sum = new BookOrder(nSum);               

            return sum;

        }

    }

}

 

namespace UseThis

{

    class OrderEngine<T>

    {

        public T AddOrder(T order1, T order2, Func<T, T, T> AddFunc)

        {

            T sum = AddFunc(order1, order2);

            return sum;

        }

    }

 

    class BookOrder

    {

        public int nTotal = 0;

        public BookOrder(int tot) { nTotal = tot; }

    }

}

7. Do Not Create Generic Specialization on Base Classes or Interfaces

When you create generic classes or methods, you are responsible for creating a set of methods that will enable developers using that class to safely use your code with minimal confusion. This means that you must pay careful attention to overload resolution. Always remember that generic methods are always perfect matches, so they win over base class methods.

class Item7

{

    /// <summary>

    /// The output of the first WriteMessage(ob) shows an important concept:

    /// WriteMessage<T>(T obj) is a better match than WriteMessage(MyBase b) for an object that is

    /// derived from MyBase. That's because the compiler can make an exact match by substituting

    /// MyDerived for T in that message, and WriteMessage(MyBase) requires an implicit conversion.

    /// </summary>

    public void Test()

    {

        Item7NS.MyDerived ob = new Item7NS.MyDerived();

 

        // Generic methods are always perfect matches, so they win over base class methods.

        WriteMessage(ob);                               // WriteMessage<T>(T ob)

 

        // The following two statements show how to control which methods get invoked

        WriteMessage((Item7NS.IMyInterface)ob);         // WriteMessage(IMyInterface ob)

        WriteMessage((Item7NS.MyBase)ob);               // WriteMessage(MyBase ob)

 

        Item7NS.MyOtherDerived ob2 = new Item7NS.MyOtherDerived();

        WriteMessage(ob2);                              // WriteMessage<T>(T ob)

        WriteMessage((Item7NS.IMyInterface)ob2);        // WriteMessage(IMyInterface ob)

 

    }

 

    private void WriteMessage(Item7NS.MyBase ob)

    {

        Trace.WriteLine("WriteMessage(MyBase ob)");

    }

    private void WriteMessage(Item7NS.IMyInterface ob)

    {

        Trace.WriteLine("WriteMessage(IMyInterface ob)");

    }

    private void WriteMessage<T>(T ob)

    {

        Trace.WriteLine("WriteMessage<T>(T ob)");

    }

}

 

namespace Item7NS

{

    class MyBase { /* Empty implementation */ }

 

    interface IMyInterface

    {

        void DoSomething();

    }

 

    class MyDerived : MyBase, IMyInterface

    {

        #region IMyInterface Members

        public void DoSomething()

        {

            Trace.WriteLine("MyDerived.IMyInterface.DoSomething");

        }

        #endregion

    }

 

    class MyOtherDerived : IMyInterface

    {

        #region IMyInterface Members

        public void DoSomething()

        {

            Trace.WriteLine("MyDerived.IMyInterface.DoSomething");

        }

        #endregion

    }

8. Prefer Generic Methods unless Type Parameters are Instance Fields

A utility class that contains generic methods can specify different constraints for each method. Those different constraints can make it much easier for the compiler to find the best match and therefore much easier for your clients to use your algorithms. Also, each generic type parameter (T in Stack<T>) need satisfy the constraints only for the methods in which it is used. With generic classes, in contrast, the generic type parameters must satisfy all the constraints defined for the complete class. As you expand a class over time, it becomes much more constraining if the generic type parameters are specified on the class level rather than at the method level.

Obviously, not every generic algorithm is suited for generic methods instead of a generic class. Some simple guidelines can help you determine which to use. In two cases you must  make a generic class: The first occurs when your class stores a value of one of the generic type parameters as part of its internal state. (Collections are an obvious example.) The second occurs when your class implements a generic interface. Except for those two cases, you can usually create a non-generic class and use generic methods. You'll end up with more granularity in your options for updating the algorithms in the future.

class Item8

{

    public void Test()

    {

        // Utilities is a generic class. Every call to methods on Utilities<> must

        // specify the generic type parameter T

        double dMax = Item8NS.Utilities<double>.Max(1.0, 1.2);

        int nMax = Item8NS.Utilities<int>.Max(3, 4);

 

        // Utilities2 is no longer a generic class. It is a non-generic class with

        // generic methods. If there is a specific version of the parameter type,

        // the compiler calls that version. If there isn't a specific version, the

        // compiler calls the generic version

        double dMax2 = Item8NS.Utilities2.Max(1.0, 1.01);

        int nMax2 = Item8NS.Utilities2.Max<int>(1, 2);

    }

}

 

namespace Item8NS

{

    /// <summary>

    /// A generic utility class rather than generic methods.  Every call to methods

    /// of this class must specify the generic type parameter.

    ///

    /// Many of the built-in types already have accessible Max and Min methods defined.

    /// Math.Max() and Math.Min() are defined for all the numeric types. Instead of using

    /// those, your generic class always picks up the version you've created using Comparer<T>.

    /// That works, but it forces extra runtime checks to determine whether a type implements

    /// IComparer<T>, followed by a call to the correct method

    /// </summary>

    /// <typeparam name="T"></typeparam>

    public static class Utilities<T>

    {

        public static T Max(T lhs, T rhs)

        {

            bool bLhsBigger = (Comparer<T>.Default.Compare(lhs, rhs) < 0);

            return (bLhsBigger) ? lhs : rhs;

        }

 

        public static T Min(T lhs, T rhs)

        {

            bool bLhsBigger = (Comparer<T>.Default.Compare(lhs, rhs) < 0);

            return (bLhsBigger) ? lhs : rhs;

        }

    }

 

    /// <summary>

    /// Utilities2 is no longer a generic class. It is a non-generic class with generic

    ///  methods. If there is a specific version of the parameter type, the compiler calls

    ///  that version. If there isn't a specific version, the compiler calls the generic

    ///  version.

    /// 

    /// Whenever you use a new type Max<T> or Min<T> , a new version of Max<T> or Min<T> is

    /// generated by the compiler. If you had instead applied the type parameter to the class

    /// declaration as in Utilities<T>, every Min or Max would be forced to hold only one type.

    /// Either approach is valid, but the semantics are very different.

    /// </summary>

    public static class Utilities2

    {

        // Generic methods

        public static T Max<T>(T lhs, T rhs)

        {

            bool bLhsBigger = (Comparer<T>.Default.Compare(lhs, rhs) < 0);

            return (bLhsBigger) ? lhs : rhs;

        }

        public static T Min<T>(T lhs, T rhs)

        {

            bool bLhsBigger = (Comparer<T>.Default.Compare(lhs, rhs) < 0);

            return (bLhsBigger) ? lhs : rhs;

        }

 

        // Overloadsc

        public static double Max(double lhs, double rhs)

        {

            return Math.Max(lhs, rhs);

        }

    }

 

}

9. Prefer Generic Tuples to Output and Ref Parameters

A common problem for many developers is how to create a method signature for methods that logically return more than one item. Many developers turn to ref or out parameters in those cases. But it's better to define generic tuples that can return multiple discrete values. A tuple is nothing more than a composite with n elements.

By creating and using tuple classes, you avoid the need to create ref and out parameters for multiple logical methods. That will make it easier to compose method calls that work with these tuples.

In general, methods that take out and ref parameters do not support composition very well.  Methods returning a single value (however complex that value might be) compose better.

class Item9

{

    public void Test()

    {

        Item9NS.Tuple<string, long> details = GetNameAndID();

    }

    private Item9NS.Tuple<string, long> GetNameAndID()

    {

        return new Item9NS.Tuple<string, long>("Yazan", 123);

    }

}

 

namespace Item9NS

{

    /// <summary>

    /// A tuple is just a composite type that n elements. Note how IEquatable<T>

    /// is defined: IEquatable<Tuple<T1, T2>> and IEquatable<T>.

    ///

    /// This tuple can be the return type for any method that has two logical return

    /// values.

    /// </summary>

    public class Tuple<T1, T2> : IEquatable<Tuple<T1, T2>>

    {

        private readonly T1 first;

        private readonly T2 second;

 

        public Tuple(T1 t1, T2 t2)

        {

            first = t1;

            second = t2;

        }

        public T1 First { get { return first;}}

        public T2 Second {get {return second;}}

 

        #region IEquatable<Tuple<T1,T2>> Members

 

        public bool Equals(Tuple<T1, T2> other)

        {

            int nFirstCompare = Comparer<T1>.Default.Compare(this.first, other.first);

            int nSecondCompare = Comparer<T2>.Default.Compare(this.second, other.second);

            bool bEqual = (nFirstCompare == 0) && (nSecondCompare == 0);               

            return bEqual;

        }

 

        #endregion

    }

}

10. Implement Class Interfaces in Addition to Generic Interfaces

Your classes will be much more useful if you support the classic non-generic interfaces in  addition to the generic interfaces you'll want to support in new libraries. In Item10NS.Name class, All the core capabilities of the equality and ordering are implemented in terms of the generic versions. But a generic implementation does not play well with any code written using the .NET 1.x methods. What's more, you may need to integrate types from various systems that represent the same logical type. For example, you may have two systems that have the concept of Order; you need a cross-type equality relationship between these two orders.

Note on IComparable<T> and IComparer<T>: These interfaces support ordering comparisons, i.e., their methods are used to indicate if two objects sort the same. IComparable<T> is often implemented by types whose values can be ordered such as SortedList<K,V>. IComparer<T> on the other hand, is not implemented on a type directly, but rather it is implemented on helper objects, typically to provide multiple sort orders

Note on Comparer<T> class: This is an abstract base class for implementation of IComparer<T>. You typically derive from this class to provide a custom implementation of the IComparer<T> interface. In addition to  deriving from this class, Comparer<T>.Default property is often used to retrieve a Comparer<T> object that uses IComparable<T> interface. For string comparisons, the StringComparer class is recommended over Comparer<String>. Properties of the StringComparer class return predefined instances that perform string comparisons with different combinations of culture-sensitivity and case-sensitivity.

namespace Item10NS

{

    /// <summary>

    /// In addition to implementing the generic IEquatable<T> and IComparable<T>, this class

    /// also implements the non-generic IComparable. Notice that the non-generic IComparable

    /// interface is defined using explicit interface implementation. This practice ensures

    /// that no one accidentally gets the classic interface instead of the preferred generic

    /// interface. In normal use, the compiler will choose the generic method over the explicit

    /// interface method. Only when the called method has been typed to the classic interface

    /// (IComparable) will the compiler generate a call to that interface member

    ///

    /// </summary>

    public class Name : IEquatable<Name>, IComparable<Name>, IComparable

    {

        private string _strFirst;

        private string _strLast;

 

        public string First

        {

          get { return _strFirst; }

          set { _strFirst = value; }

        }

 

        public string Last

        {

          get { return _strLast; }

          set { _strLast = value; }

        }

 

        #region IEquatable<Name> Members

        public bool Equals(Name other)

        {

            // If null is passed, equality should be false

            if (object.ReferenceEquals( other, null)) return false;

 

            int nFirstComp = StringComparer.CurrentCulture.Compare(this.First, other.First);

            int nSecondComp = StringComparer.CurrentCulture.Compare(this.Last, other.Last);

            return ((nFirstComp == 0) && (nSecondComp == 0));

        }

        #endregion

 

        #region IComparable<Name> Members

        public int CompareTo(Name other)

        {

            // If null is passed in, indicate that this object is greater

            if (Object.ReferenceEquals( null, other)) return 1;

 

            int nFirstComp = StringComparer.CurrentCulture.Compare( this.First, other.First);

            if (nFirstComp != 0) return nFirstComp;

 

            int nSecondComp = StringComparer.CurrentCulture.Compare( this.Last, other.Last);

            return nSecondComp;

        }

        #endregion

 

        #region IComparable Members

        int IComparable.CompareTo(object obj)

        {

            if (obj.GetType() != this.GetType())

                throw new InvalidOperationException("obj is not a Name object");

 

            return this.CompareTo(obj as Name);

        }

        #endregion

 

        // Implementing IEquatable<T> means implementing operator== and operator!=

        public static bool operator ==(Name lhs, Name rhs)

        {

            if (lhs == null) return (rhs == null);

            return lhs.Equals(rhs);

        }

 

        public static bool operator !=(Name lhs, Name rhs)

        {

            if (lhs == null) return (rhs != null);

            return !lhs.Equals(rhs);

        }

 

        // Implementing IComparable<T> implies there is an ordering relation. We should therefore implement

        // operator <, >, <=, and >=

        public static bool operator <(Name lhs, Name rhs)

        {

            if (lhs == null) return (rhs != null);

            return (lhs.CompareTo(rhs) < 0);

        }

 

        public static bool operator >(Name lhs, Name rhs)

        {

            if (lhs == null) return false;

            return (lhs.CompareTo(rhs) > 0);

        }

 

        public static bool operator <=(Name lhs, Name rhs)

        {

            if (lhs == null) return true;

            return (lhs.CompareTo(rhs) <= 0);

        }

 

        public static bool operator >=(Name lhs, Name rhs)

        {

            if (lhs == null) return (rhs == null);

            return (lhs.CompareTo(rhs) >= 0);

        }

    }

}

Multithreading

11. Use the Thread Pool Instead of Creating New Threads

You can't know the optimum number of threads that should be created for your application. However, the .NET thread pool has all the knowledge necessary to optimize the number of active threads on the target system. Furthermore, if you have created too many tasks and threads for the target machine, the thread pool queues up additional requests until a new background thread is available.

QueueUserWorkItem uses the thread pool to manage resources for you. You queue up a worker item, and when a thread is available, it executes your thread procedure. The thread pool's job is to
make sure that a thread becomes available quickly. Essentially, you fire the request and forget it

All threads belonging to the thread pool used by QueueUserWorkItem are background threads. This means that you don't need to clean up those threads before your application exits. If your application exits while these background threads are running, the system stops those tasks and unloads everything related to your application. You need to ensure that you stop all non-background threads in your application before the system will unload your application.

On the other hand, because background threads are killed without warning, you need to be careful how you access system resources to ensure that application termination at the wrong time doesn't leave the system in an unstable state. In many cases, when a thread is terminated, the runtime raises a ThreadAbortException on that thread. When an application terminates with background threads running, those background threads receive no notification that the application is terminating. They are simply stopped. If your threads may leave system resources in an unstable state, you should not use background threads.

Two important factors result in the higher performance of the thread pool compared with creating your own threads manually. First, the thread pool reuses threads as they become available for work. When you manually create new threads, you must create a new thread for each new task. The creation and destruction of those threads take more time than the .NET thread pool management.

Second, the thread pool manages the active number of threads for you. If you create too many threads, the system queues them up, and they wait to execute until enough resources are available. QueueUserWorkItem hands work to the next available thread in the thread pool and does some thread resource management for you. If all the threads in the application's thread pool are busy, it queues tasks to wait for the next available thread.

12. Use BackgroundWorker for Cross-Thread Communication

The BackgroundWorker class is built on top of ThreadPool and adds many features for inter-thread communication:

  1. The single most important issue you must deal with is exceptions in your WaitCallback, the method that does the work in the background thread. If any exceptions are thrown from that method, the system will terminate your application. It doesn't simply terminate that one background thread; it terminates the entire application. With BackgroundWorker on the other hand catches all exceptions thrown in the thread function and propagates these exceptions to the RunWorkerCompletedEventArgs.Error property.

  2. The thread function for a BackgroundWorker. QueueUserWorkItem doesn't have any built-in capability to handle reporting errors.

  3. QueueUserWorkItem does not give you any built-in methods to communicate between the background threads and the foreground thread. It doesn't provide any built-in means for you to detect completion, track progress, pause tasks, or cancel tasks. When you need those capabilities, you must use BackgroundWorker component, which is built on top of the QueueUserWorkItem functionality. You don't have to design your own communication protocols between foreground and background threads.

  4. The BackgroundWorker class performs its background tasks using ThreadPool and by using QueueUserWorkItem internally. BackgroundWorker uses events to communicate between the foreground and background threads.

  5. BackgroundWorker for multiple background requests. You need to check the IsBusy property of BackgroundWorker to see whether BackgroundWorker is currently running a task. When you need to have multiple background tasks running, you can create multiple BackgroundWorker objects. Each will share the same thread pool, so you have multiple tasks running just as you would with QueueUserWorkItem. You need to make sure that your event handlers use the correct sender property. This practice ensures that the background threads and foreground threads are communicating correctly.

class Item12

{

    private int numberToCompute = 0;

    private int highestPercentageReached = 0;

 

    public void TestBackgroundWorker()

    {

        // Create a BackgroundWorker object and set its events to control and monitor

        // the the background thread

        BackgroundWorker bw = new BackgroundWorker();

        bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);

        bw.Disposed += new EventHandler(bw_Disposed);

        bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);

        bw.DoWork += new DoWorkEventHandler(bw_DoWork);

 

        // These properties control how the foreground and background threads interact

        bw.WorkerReportsProgress = true;

        bw.WorkerSupportsCancellation = true;

 

        // Setup the thread function and start it

        numberToCompute = 100;

        highestPercentageReached = 0;           

        bw.RunWorkerAsync(numberToCompute);

 

    }

 

    # region Event handlers for BackgroundWorkder in TestBackgroundWorker

 

    /// <summary>

    /// Background thread is finished when the DoEvent handler function exits.

    /// </summary>

    void bw_DoWork(object sender, DoWorkEventArgs e)

    {

        BackgroundWorker bw = sender as BackgroundWorker;

        e.Result = ComputeFibonacci((int)e.Argument, bw, e);

    }   // RunWorkerCompleted event fired here.

 

    /// <summary>

    /// Note the RunWorkerCompletedEventArgs.Error property that contains

    /// any exception information generated by the thread function.

    /// </summary>

    void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)

    {

        if (e.Cancelled)

            Trace.WriteLine("Operation cancelled");

        else if (e.Error != null)

            Trace.WriteLine("Error: " + e.Error.Message);

        else

            Trace.WriteLine("Result: " + e.Result.ToString());

    }

 

    void bw_Disposed(object sender, EventArgs e)

    {

        Trace.WriteLine("");

    }

 

    void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)

    {

        Trace.WriteLine("Progress: " + e.ProgressPercentage);

    }

    #endregion

 

    // This is the method that does the actual work. For this

    // example, it computes a Fibonacci number and

    // reports progress as it does its work.

    long ComputeFibonacci(int n, BackgroundWorker worker, DoWorkEventArgs e)

    {

        // The parameter n must be >= 0 and <= 91. Fib(n), with n > 91, overflows a long.

        // Note that the exception will be reported in RunWorkerCompletedEventArgs.Error

        // property

        if ((n < 0) || (n > 91))

            throw new ArgumentException("value must be >= 0 and <= 91", "n");

 

        long result = 0;

 

        // Abort the operation if the user has canceled.

        // Note that a call to CancelAsync may have set

        // CancellationPending to true just after the

        // last invocation of this method exits, so this

        // code will not have the opportunity to set the

        // DoWorkEventArgs.Cancel flag to true. This means

        // that RunWorkerCompletedEventArgs.Cancelled will

        // not be set to true in your RunWorkerCompleted

        // event handler. This is a race condition.

        if (worker.CancellationPending)

        {

            e.Cancel = true;

        }

        else

        {

            if (n < 2)

            {

                result = 1;

            }

            else

            {

                result = ComputeFibonacci(n - 1, worker, e) +

                         ComputeFibonacci(n - 2, worker, e);

            }

 

            // Report progress as a percentage of the total task.

            int percentComplete = (int)((float)n / (float)numberToCompute * 100);

            if (percentComplete > highestPercentageReached)

            {

                highestPercentageReached = percentComplete;

                worker.ReportProgress(percentComplete);

            }

        }

 

        return result;

    }

}

13. Use lock() as Your First Choice for Synchronization

The lock statement generates exactly the same code as if you used Monitor.Enter() and Monitor.Exit() correctly. Furthermore, it's easier and it automatically generates all the exception-safe code you
need. The lock statement automatically generates exception-safe code. Also, it generates more-efficient code than Monitor.Enter() and Monitor.Exit(), because it needs to evaluate the target object only once. So, by default, you should use the lock statement to handle the synchronization needs.

class Item13

{

    private object _obLock = new object();

    private int _nTotal = 0;

 

    // The following two methods are identical

    public void IncrementTotalWithLock()

    {

        lock (_obLock)

        {

            _nTotal++;

        }

    }

    public void IncrementTotalWithMonitor()

    {

        System.Threading.Monitor.Enter(_obLock);

        try

        {

            _nTotal++;

        }

        finally

        {

            System.Threading.Monitor.Exit(_obLock);

        }

    }

 

    /// <summary>

    /// Monitor.Enter locks a box containing _nTotal while Monitor.Exit unlocks

    /// a different box containing _nTotal

    /// </summary>

    public void IncrementTotal_Wrong1()

    {

        // Multiple threads call Monitor.Enter successfully because each thread is locking

        // a different object (eacah call to Enter creates a different box for _nTotal)

        System.Threading.Monitor.Enter(_nTotal);

        try

        {

            _nTotal++;

        }

        finally

        {

            // SynchronizationLockException because Monitor.Exit is attempting to unlock

            // an object that was no locked in the first case (call to Monitor.Exit creates

            // yet another object containing _nTotal)

            System.Threading.Monitor.Exit(_nTotal);

        }

    }

 

    public void IncreamentTotal_WithTimeout()

    {

        if (Monitor.TryEnter(_obLock, 1000))

        {

            try

            {

                _nTotal++;

            }

            finally

            {

                Monitor.Exit(_obLock);

            }

        }

        else

            throw new SynchronizationLockException("Timeout expired on _obLock");

    }

 

    public void IncreamentTotal_WithTimeout_Better()

    {

        using (LockHolder lh = new LockHolder( _obLock, 1000))

        {

            if (lh.Locked)

            {

                _nTotal++;

            }

        }   // Monitor.Exit called here

    }

}

 

/// <summary>

/// Class to wraps Monitor.Enter/Exit calls

/// </summary>

class LockHolder : IDisposable

{

    private bool _bLocked = false;

    private object _obLock = null;

    public LockHolder(object obLock, int nMillisecondTimeout)

    {

        _bLocked = Monitor.TryEnter(obLock, nMillisecondTimeout);

        _obLock = obLock;

    }

 

    public bool Locked

    {

        get { return _bLocked; }

        set { _bLocked = value; }

    }

 

    #region IDisposable Members

    public void Dispose()

    {

        if (Locked)

        {

            Monitor.Exit(_obLock);

            Locked = false;

        }

    }

    #endregion

}

14. Use the Smallest Possible Scope for Lock Handles

In object-oriented programming, you use private member variables to minimize the number of locations you need to search for state changes. In concurrent programs, you want to do the same thing by localizing the object that you use to provide synchronization. Two of the most widely used locking techniques are just plain wrong when seen from that viewpoint. lock(this) and lock(TypeOf(MyType)) have the nasty effect of creating your lock object based on a publicly accessible instance.

The best approach is to create a handle (_obLock of type System.Object) that can be used to protect access to the shared resources of a type, say MyType. _obLock is a private member variable of MyType and therefore cannot be accessed outside MyType. You can ensure that _obLock which is used to synchronize access is private and is not accessible by any non-private properties of MyType. That policy ensures that any lock primitives on a given object are local to a given location.

If you create or use a lock inside a lambda expression, however, you must be careful. The C# compiler creates a closure around lambda expressions. This, combined with the deferred execution model supported by C# 3.0 constructs, means that it will be difficult for developers to determine when the lexical scope of the lock ends. That makes this approach more prone to deadlock issues, because developers may not be able to determine whether code is inside a locked scope.

class Item14

{

    public Item14NS.LockingDemo dnu = new Item14NS.LockingDemo();

    /// <summary>

    /// Bad locking strategy.

    /// In this call, the calling thread acquires a lock on dnu by virtue of calling lock(this)

    ///  ('this' and 'dnu' represent the same object.) However, if different threads were calling

    ///  TestBadLockApproach1, then a deadlock situation can potentially arise as dnu is publicly

    ///  accessible, and different codes my actually call lock(dnu). At one point this will lead

    ///  to a deadlock as we do not know who is locking 'dnu'

    /// </summary>

    public void TestLockingApproaches()

    {           

        dnu.MethodWithBadLock();

        dnu.Method1WithGoodLock();

        dnu.Method2WithGoodLock();

        Item14NS.LockingDemo.StaticMethodWithGoodLock();

    }

}

 

namespace Item14NS

{

    class LockingDemo

    {

        private int _nSum = 0;

        private object _obInstanceLock = new object();

 

        static int _nStaticSum = 0;

        static private object _obStaticLock = new object();

        public void MethodWithBadLock()

        {

            // Do not use lock(this)

            lock(this)

            {

                _nSum++;

            }

        }

 

        public void Method1WithGoodLock()

        {

            // Use this approach

            lock (_obInstanceLock)

            {

                _nSum++;

            }

        }

 

        /// <summary>

        /// Same as Method1WithGoodLock buts shows that there is no need to lock the

        /// entire function.

        /// </summary>

        public void Method2WithGoodLock()

        {               

            Func1WithNoSynchronization();

 

            lock (_obInstanceLock)

            {

                _nSum++;

            }

 

            Func2WithNoSynchronization();

        }

 

        static public void StaticMethodWithGoodLock()

        {

            // Use this approach

            lock (_obStaticLock)

            {

                _nStaticSum++;

            }

        }

 

        private void Func1WithNoSynchronization() { /* Add any implementation here*/ }

        private void Func2WithNoSynchronization() { /* Add any implementation here*/ }

    }

}

15. Avoid Calling Unknown Code in Locked Sections

If you invoke unknown code from inside a synchronized region of code, you introduce the possibility that another thread will deadlock your application. The pattern is similar. Your class acquires a lock. Then, while still in the synchronized section (i.e., inside a lock), it invokes a method (say an event) that calls code beyond your control (event handler), which in turn may call back into your class possibly on a different  thread.

Look at WorkerClass class in the code below. The RaiseProgress event notifies all listeners of updated progress. ob_RaiseProgress handles the RaisProgress event and calls back into the sender to retrieve progress value. Everything works fine because the event handler will run in the context of a background thread. However, suppose this application were a Windows Forms application, and you needed to marshal the event handler back to your UI thread. Control.Invoke marshals the call to the UI thread, if necessary. Furthermore, Control.Invoke blocks the original thread until the target delegate has completed. Your event handler makes a callback into the engine object in order to get the progress details. The Progress accessor, now running on a different thread, can't acquire the same lock. The UI thread is trying to lock the same handle already locked in the background thread. But the background thread is suspended waiting for the event handler to return, and the background thread already has the synch handle locked. You're deadlocked!

Because you cannot know what actions may be taken by code outside your control, you should try to avoid invoking the callback from inside the locked region. In this example, this means that you must raise the progress-reporting event from outside the locked section.

class Item15

{

    public void TestUnknownCodeCallingIntoSynchedCode()

    {

        // Create object and hookup events.

        System.Threading.Thread.CurrentThread.Name = "Item15Thread";

        Item15NS.WorkerClass ob = new Item15NS.WorkerClass();

        ob.RaiseProgress += new EventHandler<EventArgs>(ob_RaiseProgress);

 

        // Call method that locks code

        ob.DoWork();

 

    }

 

    /// <summary>

    /// Event handler that calls back into the sender. Calling into the sender attempts to acquire a

    /// lock that is already acquired by the code that fired the event in the first place.

    /// </summary>

    void ob_RaiseProgress(object sender, EventArgs e)

    {

        Item15NS.WorkerClass ob = sender as Item15NS.WorkerClass;

        Trace.WriteLine("ThreadName: " + System.Threading.Thread.CurrentThread.Name + ". Progress: " + ob.Progress);

    }

}

 

namespace Item15NS

{

    public class WorkerClass

    {

        private int progressCounter = 0;           

        private object syncHandle = new object();

        public event EventHandler<EventArgs> RaiseProgress;

 

        public void DoWork()

        {

            for (int count = 0; count < 100; count++)

            {

                lock (syncHandle)

                {

                    System.Threading.Thread.Sleep(100);

                    progressCounter++;

 

                    // An event is raised from within a syncrhonized region. Not good

                    // Move this block of code just outside the lock scope (see commented code)

                    if (RaiseProgress != null)

                        RaiseProgress(this, EventArgs.Empty);

                }

 

                //Comment RaiseProgress event raising inside lock and uncomment this code

                // for proper operation

                /*if (RaiseProgress != null)

                    RaiseProgress(this, EventArgs.Empty);

                */

            }

        }

 

        public int Progress

        {

            get { lock (syncHandle) { return progressCounter;} }

        }

    }

}

16. Understand Cross-Thread Calls in WPF

To handle cross-thread calls in WPF, you use the System.Windows.Threading.Dispatcher methods Invoke() and BeginInvoke(). This is because all function calls to each control must be on the same
thread that created the control. See Item16NS.WPFControlExtensions class.

namespace Item16NS

{

    /// <summary>

    ///  The following ControlExtensions static class contains generic methods for any invoke delegate

    ///  having up to two parameters. You can add more overloads by adding more parameters. Further,

    ///  it contains methods that use those delegate definitions to call the target, either directly or

    ///  through the marshalling provided by Dispatcher

    /// 

    /// Typical usage is:

    ///     this.InvokeIfNeeded( (() => toolStripStatusLabel1.Text = "Test"), DispatcherPriority.Normal);

    ///    

    ///  Inside the ControlExtensions class, the generic method handles the check for CheckAccess, meaning

    ///  that you don't need to remember it each time.        

    /// </summary>

    public static class WPFControlExtensions

    {

        public static void InvokeIfNeeded(this DispatcherObject ctl, Action doit, DispatcherPriority priority)

        {               

            if (!ctl.Dispatcher.CheckAccess())

            {                   

                ctl.Dispatcher.Invoke(priority, doit);

            }

            else

            {

                doit();

            }

        }

        public static void InvokeIfNeeded<T>( this DispatcherObject ctl, Action<T> doit, T args, DispatcherPriority priority)

        {

            if (!ctl.Dispatcher.CheckAccess())

            {

                ctl.Dispatcher.Invoke(priority, doit, args);

            }

            else

            {

                doit(args);

            }

        }

    } 

}

Design

17. Create Composable APIs for Sequences

C# iterators enable you to create methods that operate on a sequence but process and returnco each element as it is requested. C# 2.0 adds the 'yield return' statement, which lets you create methods that return sequences. These iterator methods have a sequence as one input (expressed as IEnumerable<T>) and produce a sequence as output (another IEnumerable<T>). By leveraging the 'yield return' statement, these iterator methods do not need to allocate storage for the entire sequence of elements. Instead, these methods ask for the next element on the input sequence only when needed, and they produce the next value on the output sequence only when the calling code asks for it.

This is a shift from the usual way of thinking to create IEnumerable<T> input and output parameters. But making that shift provides many benefits; you can apply multiple operations while iterating a sequence only once, increasing runtime efficiency. Each iterator method executes the code to produce the Nth element when that element is requested and not before. This deferred execution model means that your algorithms use less storage space and compose better than traditional imperative methods. See TestIterators() and TestGenericIterators() methods.

Note that iterator methods do not mutate the source sequence. Instead, they produce a new sequence as output. If the sequence contains reference types, however, the items may be modified. Multiple iterators can therefore be combined to produce complex algorithms; When you create these small iterator methods, it is much simpler to create complicated algorithms that are a single pipeline of many small transformations. See TestAllIterators() method below:

class Item17

{

    /// <summary>

    /// The following function shows how to use 'yield return' and generates the following output:

    ///

    ///    Entering UpdatePrice

    ///    Evaluating 1

    ///Updated price: 10

    ///

    ///    Re-entering after yield return

    ///    Evaluating 2

    ///Updated price: 20

    ///

    ///    Re-entering after yield return

    ///    Evaluating 3

    ///Updated price: 30

    ///

    ///    Re-entering after yield return

    ///    Evaluating 4

    ///Updated price: 40

    ///

    ///    Re-entering after yield return

    ///    Evaluating 5

    ///Updated price: 50

    ///

    ///    Re-entering after yield return

    ///    Exiting UpdatePrice

    /// </summary>

    public void TestIterators()

    {

        // Create a test list

        List<int> lstPrices = new List<int>() { 1, 2, 3, 4, 5 };

 

        // Call a function that uses 'yield return'. Observe trace outputs

        foreach (int n in UpdatePrice(lstPrices, 10))

            Trace.WriteLine("Updated price: " + n + Environment.NewLine);

    }

 

    /// <summary>

    /// The following function shows how to use 'yield return' on a generic type,

    /// and generates the following output:

    ///    Entering GenericUpdatePrice

    ///    Evaluating 1

    ///Updated price: -10

    ///

    ///    Re-entering after yield return

    ///    Evaluating 2

    ///Updated price: -20

    ///

    ///    Re-entering after yield return

    ///    Evaluating 3

    ///Updated price: -30

    ///

    ///    Re-entering after yield return

    ///    Evaluating 4

    ///Updated price: -40

    ///

    ///    Re-entering after yield return

    ///    Evaluating 5

    ///Updated price: -50

    ///

    ///    Re-entering after yield return

    ///    Exiting GenericUpdatePrice

    /// </summary>

    public void TestGenericIterators()

    {

        // Create a test list

        List<int> lstPrices = new List<int>() { 1, 2, 3, 4, 5 };

 

        foreach (int n in GenericUpdatePrice<int>(lstPrices, -10, UpdatePriceFunc))

            Trace.WriteLine("Updated price: " + n + Environment.NewLine);

    }

 

    /// <summary>

    /// Creating simple iterators with 'yield return' allows you to construct complex

    /// pipelined algorithms

    /// </summary>

    public void TestAllIterators()

    {

        // Create a test list

        List<int> lstPrices = new List<int>() { 1, 2, 3, 4, 5 };

        List<int> lstTempPrices = new List<int>();

        List<int> lstModifiedPrices = new List<int>();

        // Call a function that uses 'yield return'. Observe trace outputs

 

        int nFactor1 = 10;

        int nFactor2 = 10;

        foreach (int n in UpdatePrice(lstPrices, nFactor1))

        {

            lstTempPrices.Add(n);

            Trace.WriteLine("Updated price: " + n + Environment.NewLine);

        }

 

        foreach (int n in GenericUpdatePrice<int>(lstTempPrices, nFactor2, UpdatePriceFunc))

        {

            lstModifiedPrices.Add(n);

            Trace.WriteLine("Updated price: " + n + Environment.NewLine);

        }

    }

 

    /// <summary>

    /// The yield return statement plays an interesting trick: It returns a value and retains

    /// information about its current location and the current state of its internal iteration

    /// </summary>

    private IEnumerable<int> UpdatePrice(IEnumerable<int> prices, int nFactor)

    {

        Trace.WriteLine("\tEntering UpdatePrice");

        foreach (int price in prices)

        {               

            Trace.WriteLine("\tEvaluating " + price);

            yield return (price * nFactor);

            Trace.WriteLine("\tRe-entering after yield return");

        }

        Trace.WriteLine("\tExiting UpdatePrice");

    }

 

    /// <summary>

    /// A generic version of UpdatePrice() function

    /// </summary>

    private IEnumerable<T> GenericUpdatePrice<T>(IEnumerable<T> prices, T nFactor, Func<T, T, T> UpdatePriceFunc)

    {

        Trace.WriteLine("\tEntering GenericUpdatePrice");

        foreach (T price in prices)

        {

            Trace.WriteLine("\tEvaluating " + price);

            yield return UpdatePriceFunc(price, nFactor);

            Trace.WriteLine("\tRe-entering after yield return");

        }

        Trace.WriteLine("\tExiting GenericUpdatePrice");

    }

 

    private int UpdatePriceFunc(int nPrice, int nFactor)

    {

        return nPrice * nFactor;

    }

}

18. Decouple Iterations from Actions, Predicates, and Functions

In many iteration functions (see Create Composable APIs for Sequences) you'll often find that iteration functions have two portions: a portion that iterated a sequence, and a portion that performs an action on each element in the sequence. In other words, the enumeration pattern is not related to the action performed on each item, and the two things should be done separately. Putting them together means tighter coupling and probably duplicated code.

The reason many developers combine various operations into one method is that the portion to be customized falls between the standard opening and closing parts of the enumeration. The only way to customize the inner portion of such an algorithm is to pass a method call or function object to the enclosing method. In C#, the way to do that is to use delegates to define the inner operation. This is exactly what has been done in function  Item17.GenericUpdatePrice() in Create Composable APIs for Sequences.

There are three main idioms that you use with anonymous delegates: functions, actions, and predicates. A 'predicate' delegate is a Boolean method that determines whether an element in a sequence matches some condition. An 'action' delegate performs some action on an element in the collection. These method signatures are so common that the .NET library contains definitions for Action<T>, Func<T, TResult>, and Predicate<T>:

namespace System
{
    public delegate bool Predicate<T>( T obj);
    public delegate void Action<T>( T obj);
    public delegate TResult Func<T, TResult>(T arg);
}

TestGeneralPredicates() function below shows how to use Predicate using anonymous delegates and lambda expressions. TestGeneralActions() shows how to use Action using anonymous delegates and lambda expressions. TestDecouplingIterations() shows illustrates the concept of decoupling iterations from actions performed on each sequence item.

class Item18

{

    /// <summary>

    /// Shows predicate usage using anonymous delegates and lambda expressions

    /// for List<T>.RemoveAll( predicate<T> match ) function. Internally, this

    /// remove function calls your delegate method successively for every item

    /// in the list. Whenever the delegate returns true, that element is removed

    /// from the list.

    /// </summary>

    public void TestGeneralPredicates()

    {

        // Create a list with data

        List<int> lstNumbers = new List<int>() { 1, 2, 3, 2, 3, 2, 2, 3};

 

        // Use an anonymous delegate to remove all items that match a specific condition

        // In this case, removes all elements whose value is 2

        int nConditionValue = 2;

        lstNumbers.RemoveAll(

            delegate(int nCollectionMember)

            {

                return nCollectionMember == nConditionValue;

            });       

 

        // Use a lambda expression to remove all items that match a specific condition

        // In this case, removes all elements whose value is 3

        nConditionValue = 3;

        lstNumbers.RemoveAll( (int nCollectionMember) => nCollectionMember == nConditionValue );

    }

 

    /// Shows action usage using anonymous delegates and lambda expressions

    /// for List<T>.ForEach( Action<T> action ) function. Internally, this

    /// ForEach function calls your delegate method successively for every item

    /// in the list and applies the Action function to each item

    public void TestGeneralActions()

    {

        // Create a list with data

        List<int> lstNumbers = new List<int>() { 1, 2, 3, 2, 3, 2, 2, 3 };

 

        // Use an anonymous delegate to visit each item in lstNumbers

        List<int> lstUpdatedNumbers = new List<int>();

        lstNumbers.ForEach(delegate(int nCollectionMember)

        {

            lstUpdatedNumbers.Add(nCollectionMember * 10);

        });

 

        // Use a lambda expression to visit each item in lstNumbers

        lstUpdatedNumbers.Clear();

        lstNumbers.ForEach((int nCollectionMember) => lstUpdatedNumbers.Add(nCollectionMember * 10));           

    }

 

    /// <summary>

    /// Shows how to decouple iteration from action or logic to be applied for each item

    /// </summary>

    public void TestDecouplingIterations()

    {

        List<int> lstNumbers = new List<int>() { 1, 2, 2, 3, 4, 5, 2 };

 

        List<int> lstFilteredNumbers = new List<int>();

        int nFilterValue = 2;

        foreach (int number in Filter(lstNumbers, (int nCollectionMember) => nCollectionMember != nFilterValue))

            lstFilteredNumbers.Add(number);

    }

 

    /// <summary>

    /// Helper method that decouples iteration logic from action to be applied to

    /// each iteration item. Note that each element in the input sequence is evaluated

    /// using the Predicate method and if the Predicate returns true, that element is

    /// returned as part of the output sequence. ~The main point is that and developer

    /// can write a method on a type that tests a condition, and the method will be

    /// compatible with this filter method

    /// </summary>

    private IEnumerable<T> Filter<T>(IEnumerable<T> input, Predicate<T> predicate)

    {

        // Check we have a valid prediate

        if (predicate == null) throw new ArgumentException("Predicate is null");

 

        foreach (T item in input)

            if (predicate(item))

                yield return item;

    }

}

19. Generate Sequence Items as Requested

It's best to generate sequence items only when each item is requested by the consumer of the sequence. You'll avoid doing extra work when the consumer needs only a portion of the algorithm to perform its work. It may be a small savings, or the savings may be much greater if the cost of creating elements is large. In any case, the code that creates the sequence will be clearer when you generate the sequence items only as needed.

class Item19

{

    /// <summary>

    /// Creates a sequence inefficiently. Note the following:

    /// 1.  First, this technique assumes that you're putting the results into a IList<double>.

    ///     If clients want to store the results in some other structure they must convert it.

    /// 2.  Creating the entire list doesn't give client code a chance to stop the generation

    ///     function based on a specified condition. It will always generate the requested number

    ///     of elements. As written, it can't be stopped if the user wants to stop the process

    ///     for paging or for any other reason.

    /// 3.  This method could be the first stage of several transformations on a sequence of data.

    ///     In that case, this method would be a bottleneck in the pipeline: Every element would

    ///     have to be created and added to the internal collection before the next step could

    ///     continue.

    ///    

    /// You can remove all those limitations by making the generation function an iterator method.

    /// See TestCreateSequenceEfficiently() method

    ///

    /// </summary>

    public void TestCreateSequenceInefficiently()

    {

        IList<double> lst = CreateSequence<double>(10, 5, 10, (int nItem) => Convert.ToDouble(nItem));

    }

    private IList<T> CreateSequence<T>(int nElementCount, int nStartAt, int nStep, Converter<int, T> converter)

    {

        List<T> lst = new List<T>();

 

        for (int i = 0; i < nElementCount; i = i + 1)

        {

            lst.Add(converter(nStartAt + (i*nStep)));

        }

        return lst;

    }

 

    /// <summary>

    /// Improves on the inefficiencies of TestCreateSequenceInefficiently() by generating a sequence

    /// of numbers via 'yield return'. This code does not make any assumptions regarding the storage

    /// location for the generated sequence. Results can be saved in a List or a BindingList or any

    /// other list

    /// </summary>

    public void TestCreateSequenceEfficiently()

    {

        Queue<double> q = new Queue<double>(CreateSequence2<double>(10, 5, 10, (int nItem) => Convert.ToDouble(nItem)));

 

        List<double> lst = new List<double>(CreateSequence2<double>(10, 5, 10, (int nItem) => Convert.ToDouble(nItem)));

 

        // The previous statement is equivlant to:

        List<double> lst2 = new List<double>();

        foreach (double item in CreateSequence2<double>(10, 5, 10, (int nItem) => Convert.ToDouble(nItem)))

            lst.Add(item);           

    }

    private IEnumerable<T> CreateSequence2<T>(int nElementCount, int nStartAt, int nStep, Converter<int, T> converter)

    {

        for (int i = 0; i < nElementCount; i = i + 1)

        {

            yield return converter(nStartAt + (i * nStep));

        }         

    }

 

    /// <summary>

    /// It's easy to stop the enumeration if you use TakeWhile<> extension method. The sequence

    /// generation short-circuits as soon as the first nonconforming value is found. That can

    /// result in a significant performance improvement.

    ///

    /// Of course, any condition can be used to determine when the enumeration should stop. You

    /// can check to see whether the user wishes to continue, poll another thread for input, or

    /// do anything else needed by your application. The enumerator method provides a simple

    /// means of interrupting the enumeration anywhere in the sequence. This deferred execution

    /// means that only the elements requested.

    /// </summary>

    public void TestStoppingSequenceGeneration()

    {

        int nStopAtValue = 20;

        IEnumerable<int> collection = CreateSequence2<int>(10, 5, 10, (int nItem) => Convert.ToInt32(nItem)).

                                            TakeWhile((int val) => val < nStopAtValue);

        List<int> lst = new List<int>();

        foreach (int item in collection)

            lst.Add(item); 

    }

}

20. Loosen Coupling by Using Function Parameters

 Using function parameters means that your component is not responsible for creating the concrete type of the classes it needs. Rather, your component uses any dependencies through an abstract definition. You can create contracts by using delegates to minimize the requirements on client code.
 
First, consider one end of the spectrum where you specify base classes: Derive from this specified  base class, implement these known abstract (or other virtual) methods, and it just works. In addition, you can implement any common functionality in the abstract base class. Users of your component do not need to re-implement any of that code. However, all .NET languages mandate single inheritance for classes. Creating a component that demands a base class can be very limiting to all users. You're mandating a certain class hierarchy. There's no other way to use it.
 
Now consider the other end of the spectrum where you create interfaces: Creating interfaces and coding against them results in looser coupling than does relying on base classes. This practice creates a relationship that's similar to using a base class. However, there are two important  differences: First, using an interface does not enforce any class hierarchy on your users. Second, you cannot easily provide a default implementation for any of the behavior necessary for client code.
 
Do you really need to define an interface or an abstract base class? Or will a more loosely coupled approach, such as defining a delegate signature, be better?
 
The reason for using delegates instead of an interface is that the delegate is not a fundamental attribute of the type. It's not the number of methods. Several interfaces in the .NET Framework contain only one method. IComparable<T> and IEquatable<T> are perfectly good interface definitions. Implementing those interfaces says something about your type: that it supports comparisons or equality. Implementing a hypothetical IPredicate<T> (see Item20NS_DoNotUse) doesn't say anything interesting about a particular type. Compare Item20NS_DoNotUse.List<T>.RemoveAll with System.Collections.Generic.List<T>.RemoveAll() which is much easier to use. However, as you loosen the coupling, you increase the amount of work you might need to do to ensure proper error handling when these decoupled components communicate. For example, suppose you've created code that defines events. You know that you must check that event member against null whenever you intend to raise that event. Client code may not have created the event handlers. You'll have the same work when you create interfaces using delegates. What is the correct behavior when your client passes a null delegate? Is it an exception, or is there a correct default behavior? What happens if client code delegates throw exceptions? Can you recover? If so, how?

Also note that when you switch from using inheritance to using delegates to define your expectations, you must understand that you have the same runtime coupling you would have by holding a reference to an object or an interface. If your object stores a copy of the delegate that it can call later, your object now controls the lifetime of the object to which that delegate refers. You may be extending the lifetime of those objects. This is no different from having your object hold a reference to an object (by storing a reference to an interface or a base class) that your object will invoke later.  It's a little harder to see by reading the code, though.

To summarize: The default choice is still to create interface contracts that mandate how your component will communicate with client code. Abstract base classes give you the extra ability to provide a default implementation of some of the work that otherwise would be done by client code. Defining delegates for the methods you expect gives you the most flexibility, but it also means you have less support from tools. You buy more work but gain greater flexibility.

class Item20

{

    public void Test1()

    {

        // One way to generate a sequence. The logic to generate the sequence is

        // contained within the CreateSequence method

        foreach (int n in Item20NS.Utility.CreateSequence(10, 0, 5))

            Trace.WriteLine(n);

 

        // A better way to generate sequences (using lambda expressions)

        int nStartAt = 0;

        int nStep = 5;

        IEnumerable<int> aSeq1 = Item20NS.Utility.CreateSequence_V2<int>(10, (i) => nStartAt + (i * nStep));

        foreach (int n in aSeq1)

            Trace.WriteLine(n);

 

        // A better way to generate sequences (using anonymous delegates)

        IEnumerable<int> aSeq2 = Item20NS.Utility.CreateSequence_V2<int>(10, delegate(int i)

            {

                return nStartAt + (i * nStep);

            });

        foreach (int n in aSeq2)

            Trace.WriteLine(n);

    }

 

    public void Test2()

    {

        // Create a sequence that will be summed

        IEnumerable<int> sequence = new int[] {1,2,3,4,5};

 

        // A simple algorithm to add up the elements of a sequence

        int nSum = Item20NS.Math.Sum(sequence);

 

        // Same as above but creates instead a general-purpose accumulator by factoring out the sum

        // operation and replacing it with a delegate;

        int nSum2 = Item20NS.Math.Sum_V2<int>(sequence, (value, total) => value + total);

    }

}

 

namespace Item20NS_DoNotUse

{

    // Improper extra coupling

    public interface IPredicate<T>

    {

        bool Match(T objectToFind);

    }

 

    public class List<T>

    {

        public void RemoveAll(IPredicate<T> predicate)

        {

            // Invoke the predicate on the collection wrapped by this instance                  

        }

    }

 

    // This class must be implemented by the user the Item20NS.List<T> class

    public class MyPredicate : IPredicate<int>

    {

        private int _nTarget;

        public bool Match(int nValue)

        {

            return nValue == _nTarget;

        }

    }

}

 

namespace Item20NS

{

    /// <summary>

    /// The following two classes illustrate how to use functions as parameters to separate algorithms

    /// from the specific data types on which they operate.

    /// </summary>

    public class Utility

    { 

        /// <summary>

        /// This version of CreateSequence contains the logic to create the sequence

        /// based on the given parameters. Compare this method with CreateSquence2

        /// </summary>

        static public IEnumerable<int> CreateSequence(int nCount, int nStart, int nStep)

        {

            for (int i = 0; i < nCount; i++)

                yield return nStart + (i * nStep);

        }

 

        /// <summary>

        /// Improved on CreateSequence method above by taking a function parameter to specify

        /// how the sequence should be generated

        /// </summary>

        static public IEnumerable<T> CreateSequence_V2<T>(int nCount, Func<int, T> generator)

        {

            for (int i = 0; i < nCount; i++)

                yield return generator(i);

        }

    }

 

    public class Math

    {

        static public int Sum(IEnumerable<int> sequence)

        {

            int nTotal = 0;

            foreach (int nItem in sequence)

                nTotal += nItem;

 

            return nTotal;

        }

 

        static public T Sum_V2<T>(IEnumerable<T> sequence, Func<T, T, T> accumulator)

        {

            if (accumulator == null) return default(T);

 

            T total = default(T);

            foreach (T item in sequence)

                total = accumulator(item, total);

 

            return total;

        }

    }

}

21. Create Method Groups That are Clear, Minimal, and Complete

It's easier to work with fewer overloaded methods than with more overloads. Your goal should be to create precisely the right number of overloads: enough of them that your type is easy for client developers to use but not so many that you complicate the API and make it harder for the compiler to create exactly the one best method.
 
A generic method becomes the best method if the compiler can perform the correct type substitution for all type parameters. Yes, even if there are obvious candidate methods that require implicit conversions, the generic method is considered a better method match whenever it is accessible.
 

namespace Item21DoNotUse

{

    /// <summary>

    /// Any methods having the same name should perform essentially the same function. For example,

    /// the 2 Add() methods should do the same thing. However, because the two Add() methods do

    /// semantically different things, then they should have different names. Therefore, when

    /// overloading methods, different overloaded methods should provide different parameter lists,

    /// never different actions.

    ///

    /// Ambiguity problems arise when methods have similar arguments and the compiler must make a

    /// choice. In the simplest case, there is only one parameter for any of the possible overloads

    /// for the Scale() methods. By creating all these overloads, you have avoided introducing any

    /// ambiguity. You probably wonder why all those Scale() overloads were not replaced with a

    /// single generic method. That's because C# generics don't support that practice in the way

    /// C++ templates do. With C# generics, you can't assume that arbitrary methods or operators

    /// are present in the type parameters (the only methods that are available are those of

    /// System.Object). You must specify your expectations using constraints. Of course, you might

    /// think about using delegates to define a method constraint. But in this case, that technique

    /// only moves the problem to another location in the code where both the type parameter and the

    /// delegate are specified.

    /// </summary>

    public class Vector

    {

        private List<double> values = new List<double>();

 

        /* ADD */

        // Add a value to the internal list.

        public void Add(double number)

        {

            values.Add(number);

        }

 

        // Add values to each item in the sequence.

        public void Add(IEnumerable<double> sequence)

        {

            int index = 0;

            foreach (double number in sequence)

            {

                if (index == values.Count)

                    return;

                values[index++] += number;

            }

        }

 

        /* SCALE */

        public void Scale(short scaleFactor)

        {

            for (int index = 0; index < values.Count; index++)

                values[index] *= scaleFactor;

        }

 

        public void Scale(int scaleFactor)

        {

            for (int index = 0; index < values.Count; index++)

                values[index] *= scaleFactor;

        }

 

        public void Scale(float scaleFactor)

        {

            for (int index = 0; index < values.Count; index++)

                values[index] *= scaleFactor;

        }

 

        public void Scale(double scaleFactor)

        {

            for (int index = 0; index < values.Count; index++)

                values[index] *= scaleFactor;

        }

    }

 }

22. Prefer Defining Methods to Overloading Operators

Overloaded operators are not CLS compliant, but each operator maps to a special method name. This practice allows languages that do not support overloaded operators to invoke overloaded operators defined in languages that allow them. The names of those overloaded operators are not necessarily friendly API names. Developers using other languages would need to call a method named op_Equality to invoke the == operator you created in C#.

The simplest decision is whether to overload operator ==. If your type overrides System.Object.Equals or implements IEquatable<T> for your type, you should overload operator ==. The C# language specification mandates that if you overload operator ==, then you must also overload operator != and override System.Object.GetHashCode(). All three of those methods must follow the same semantics for equality, although the language cannot enforce that. To enforce it, you must implement those methods correctly. It follows that if you overload operator ==, then you must implement IEquatable<T> and override System.Object.Equals().

The next most common set of overloaded operators is the comparison operators. If you implement IComparable<T> for your type, you should also overload operator< and operator>.  If your type also implements IEquatable<T>, you should also overload operator <= and operator >=. As with operator ==, the C# specification mandates that you must overload those operators in pairs. Overloading operator< means that you must overload operator>,  and overloading operator <= means that you must overload operator >=.

Notice that in both of those descriptions, the directive is to overload operators when your type defines methods that implement the same functionality using standard .NET interfaces. That's the most important point in this item: Whenever you define overloaded operators, you must provide an alternative public api that implements the same behavior. If you fail to do this, it means that your type will be much less friendly to developers who are using languages that don't support operator overloading. Once you move beyond the equality and ordering relations, it's much less likely that you'll overload operators. It's also much less clear-cut when you should overload operators.

You should consider overloading the mathematical operators if your type models numeric data. More importantly, remember that you must provide an alternative for languages that don't support operator overloading. Defining operator + means that you should create an Add() method.(System.String has a Concat() method, which is consistent with the semantics of + for strings.)

You'll find that it's much easier to define the set of operators you want to overload by first defining the set of methods you want to support and then deriving the operators you want to support based on the methods your type supports. For example, if you create Add() and Subtract(), you should define operator+ and operator- but probably not any other mathematical operators. If you define multiple Add() methods with dissimilar parameters, you should define multiple operator+ overloads. Furthermore, because addition is commutative, you should define operator+ methods with both parameter orderings. If A+B is valid, then B+A is also valid, and it must produce the same result even if A and B are different types (except for System.String).

Therefore, to summarize: Start your design by defining your type's public interface using CLS-compliant members. Once you have done that, consider implementing overloaded operators for those languages that support types. The most common operators you will overload are operator == and operator !=. You must overload those when your type implements IEquatable<T>. Many C# developers use the operators and expect them to behave consistently with the IEquatable<T>.Equals() method.  You'll also overload the comparison operators: <, >, <=, and >=. You should implement those when your type implements IComparable<T>.

23. Understand How Events Increase Runtime Coupling Among Objects

Events can provide a way to completely decouple your class from those types it needs to notify: You provide outgoing event definitions and subscribers, whatever type they might be, subscribe to those events. Inside your class, you raise the events. Your class knows nothing about the subscribers, and it places no restrictions on the classes that can implement those interfaces. Any code can be extended to subscribe to those events and create whatever behavior they need when those events are raised. However, there can be some complex coupling issues related to event-based APIs. See Item23NS.MyClass class below.

If you need to ensure that there is exactly one subscriber, you must choose another way of communicating with any interested code rather than using events. For example, you can

Then your single subscriber can decide whether it wants to support multiple subscribers and how to orchestrate the semantics of cancel requests.

At runtime, there's another form of coupling between event sources and event subscribers. Your event source holds a reference to the delegate that represents the event subscriber. The event subscriber's object lifetime now will match the event source's object lifetime. The event source is now a root for the event subscriber. As long as the event source holds the reference and is reachable, the event subscriber is also reachable and therefore is not eligible for garbage collection. Even if the event subscriber would otherwise be eligible for destruction, the delegate handle in the event source keeps a live root, and keeps it alive.

As a result, event subscribers need to modify their implementation of the dispose pattern to unhook event handlers as part of the Dispose() method. Otherwise, subscriber objects continue to live on because reachable delegates exist in the event source object. It's another case where runtime coupling can cost you. Even though it appears that there is looser coupling because the compile-time dependencies are minimized, runtime coupling does have costs.

Event-based communication loosens the static coupling between types, but it comes at the cost of tighter runtime coupling between the event generator and the event subscribers. The multicast nature of events means that all subscribers must agree on a protocol for responding to the event source. The event model, in which the event source holds a reference to all subscribers, means that all subscribers must either (1)remove event handlers when the subscriber wants to be disposed of or (2) simply cease to exist. Also, the event source must unhook all event handlers when the source should cease to exist. You must factor those issues into your design decision to use events.

namespace Item23NS

{

    public class MyEventArgs : EventArgs

    {

        private bool _bCancel;

        public bool Cancel

        {

            get { return _bCancel; }

            set { _bCancel = value; }

        }

    }

 

    /// <summary>

    /// MyClass contains the OnStart event whos argument type (MyEventArgs) contains a Cancel

    /// flag. Suppose that there are multiple subscribters to OnStart; One subscriber might request

    /// a cancel, and the second might reverse that request. The foregoing definition does not

    /// guarantee that this behavior can't happen. Having multiple subscribers and a mutable event

    /// argument means that the last subscriber in the chain can override every other subscriber.

    /// There's no way to enforce having only one subscriber, and there is no way to guarantee that

    /// you're the last subscriber. You could modify the event arguments Cancel flag to ensure that

    /// once the cancel flag is set, no subscriber can turn it off (see MyEventArgs2)

    /// </summary>

    public class MyClass

    {

        private event EventHandler<MyEventArgs> OnStart;

 

        public void RunProcess()

        {

            // Add code to run some specific process

            // ...

 

            // Let all subscribers know that a process has been started

            MyEventArgs args = new MyEventArgs();

            args.Cancel = false;

            if (OnStart != null)

            {

                // Fires event on each subscriber that has a handler for this event

                OnStart(this, args);

            }

 

            // Cancel process if a user sets MyEventArgs.Cancel to true

            // But what if one user sets MyEventArgs.Cancel to true and then

            // another user sets it to false? See MyEVentArgs2 class

            if (args.Cancel == true)

            {

                // Add logic to cancel process

            }

        }

    }

 

    /// <summary>

    /// Improves on MyEventArgs class by ensuring that once the Cancel flag is set to true, no subscriber

    /// can reset it back to false. Note the use of assymetric accessor on Cancel's set property.

    /// </summary>

    public class MyEventArgs2 : EventArgs

    {

        private bool _bCancel;

        public bool Cancel

        {

            get { return _bCancel; }

            private set { _bCancel = value; }

        }

 

        public void CancelRequest()

        {

            Cancel = true;

        }

    }

}

24. Declare Only Non-virtual Events

Note 1: Read sections 10.8.1 and 10.8.4 in C# specification which can be found at http://msdn.microsoft.com/en-gb/vcsharp/aa336809.aspx.
Note 2: For a quick referesher on field-like events and user-defined events, see namespace Item24NS1 below

For this item, the following is relevant 'event' information taken from the C# specification document:

  1. A virtual event declaration specifies that the accessors (i.e. get and set) of that event are virtual. The virtual modifier applies to both accessors of an event.
     

  2. The accessors of an inherited virtual event can be overridden in a derived class by including an event declaration that specifies an override modifier. This is known as an overriding event declaration. An overriding event declaration does not declare a new event. Instead, it simply specializes the implementations of the accessors of an existing virtual event.
     

  3. Within the program text of the class or struct that contains the declaration of an event, certain events can be used like fields. To be used in this way, an event must not be abstract or extern, and must not explicitly include event-accessor-declarations. Such an event can be used in any context that permits a field. The field contains a delegate (§15) which refers to the list of event handlers that have been added to the event. If no event handlers have been added, the field contains null.

Item 3 means that declaring a virtual field-like event will cause the compiler to generate a delegate field to back the event, and virtual accessors for the event. Declaring an overriding field-like event will not cause the compiler to generate a new backing field for the overriding event in the case of field-like events, but will cause it to generate overriding accessors. For a full example, see Item24NS2 and TestVirtualEvents() method below.

The moral of the story is this: If you have a virtual event, have a virtual triggering method.  If you override a virtual event, override its trigger method as well.

internal class Item24

{

    internal void TestEvents1()

    {

        // Hook up events

        EventDemo ob = new EventDemo();

        ob.OnProgress1 += new delProgress(ob_OnProgress1);

        ob.OnProgress2 += new delProgress(ob_OnProgress2);

 

        // Call methods on 'ob' to fire events

        ob.ShowProgress1();

        ob.ShowProgress2();

    }

 

    internal void TestVirtualEvents()

    {

        // Static type is P. Run-time type is D

        D derived = new D();

        P parent = derived;

 

        // Hook up handlers for case1_event through derived and parent classes

        parent.case1_event += new EventHandler(parent_case1_event);

        derived.case1_event += new EventHandler(derived_case1_event);

 

        // Fire both events. Note the following:

        // The compiler does not generate a protected backing field on the parent class P. Instead, it

        // generates two private backing fields - one in P and one in D. Secondly, when we execute both

        // functions below, we'll see that it is the derived delegate field that gets both of the handlers

        // hooked up to it.

        derived.DerivedCase1Event();    // Calls derived_case1_event() and parent_case1_event() handlers

        parent.ParentCase1Event();      // Calls nothing as parent.case1_event is null

 

        // Using workaround

        derived.RaiseCase1Event();

        parent.RaiseCase1Event();

    }

 

    void derived_case1_event(object sender, EventArgs e)

    {

        Trace.WriteLine("derived_case1_event");

    }

 

    void parent_case1_event(object sender, EventArgs e)

    {

        Trace.WriteLine("parent_case1_event");

    }

 

    void ob_OnProgress2(double dPercent)

    {

        Trace.WriteLine("ob_OnProgress2");

    }

 

    void ob_OnProgress1(double dPercent)

    {

        Trace.WriteLine("ob_OnProgress1");

    }

}

 

namespace Item24NS

{

    internal delegate void delProgress(double dPercent);

 

    /// <summary>

    /// Conceptually, an event is a pair of methods: add accessor and remove accessor.

    /// Each method takes a single parameter of a specific delegate type. 'add' and

    /// 'remove' accessors are invoked via 'e+=d' and 'e-=d' expressions, respectively.

    /// </summary>

    internal class EventDemo

    {

        // _del is a reference type of type delProgress

        private delProgress _del;

 

        // Declare the OnProgress1 event using field-like syntax. In this syntax, the

        // event is declared with no add or remove accessors. The compiler automatically

        // generates default accessors (similar to those that were manuall defined for

        // OnProgress2 event), and add an anonymous private delegate that stores the

        // invocation list for the event

        internal event delProgress OnProgress1;

 

        // Declare the OnProgress2 event using manual syntax. With this syntax,

        // it is obvious that events are similar to properties, except that both

        // accessors (add and remove) must always be present

        private object _obLock = new object();

        internal event delProgress OnProgress2

        {

            add

            {

                lock (_obLock) { _del += value; }

            }

            remove

            {

                lock (_obLock) { _del -= value; }

            }

        }

 

        // Public inteface

        public void ShowProgress1()

        {

            // OnProgress1 is a field-like event, but the following calls refer

            // not to the event itself, but to the anonymous private delegate

            // created by the compiler.

            if (OnProgress1 != null)

                OnProgress1(0.1);

        }

 

        public void ShowProgress2()

        {

            // OnProgress2 event was created manually. Note here that unlike

            // OnProgress1 event, we have to use the underlying delegate for

            // OnProgress2 event

            if (_del != null)

                _del(0.3);

        }

    }

 

    internal class DerivedEventDemo : EventDemo

    {

        public void ShowProgress1FromDerived()

        {

            // The following code does not compile because the derived class does

            // not have access to the compiler-generated private anonymous delegate

            // Error: The event 'MoreEffectiveCS.Design.Item24NS.EventDemo.OnProgress1'

            // can only appear on the left hand side of += or -= (except when used from

            // within the type 'MoreEffectiveCS.Design.Item24NS.EventDemo')

            /*

            if (base.OnProgress1 != null)

                base.OnProgress1(0.5);

            */

        }

    } 

}

 

namespace Item24NS2

{

    /// <summary>

    /// Consider a parent class P which declares a virtual event, and some derived

    /// class D which overrides it. Note that there are four combinations with respect

    /// to usage of field-like or user-defined syntaxes:

    ///     1. P declares a field-like event. D declares a field-like event

    ///     2. P declares a field-like event. D declares a user-defined event

    ///     3. P declares a user-defined event. D declares a field-like event

    ///     4. P declares a user-defined event. D declares a user-defined event

    ///    

    /// </summary>

    class P

    {

        // P contains an automatically-generated private delegate field backing case1_event,

        // and two virtual accessors that add and remove from the delegate

        public virtual event EventHandler case1_event;

 

        // P contains an automatically-generated private delegate field backing case2_event,

        // and two virtual accessors that add and remove from the delegate

        public virtual event EventHandler case2_event;

 

 

        public virtual event EventHandler case3_event

        {

            add { }

            remove { }

        }

        public virtual event EventHandler case4_event

        {

            add { }

            remove { }

        }

 

        public void ParentCase1Event()

        {

            // case1_event will be null!

            if (case1_event != null)

                case1_event(this, null);

        }

 

        public virtual void RaiseCase1Event()

        {

            if (case1_event != null)

                case1_event(this, null);

        }

    }

 

    class D : P

    {

        // D.case1_event contains two overriding accessors, who add and remove from the delegate

        // contained in P. Notice that for this to work, the delegate in P must be elevated from

        // private to protected

        public override event EventHandler case1_event;

 

        // D does not have access to P.case2_event's backing field.

        public override event EventHandler case2_event

        {

            add { }

            remove { }

        }

 

        // D has a backing field generated for case3_event, which is private

        public override event EventHandler case3_event;

 

        // This is just the typical virtual/override pattern.

        public override event EventHandler case4_event

        {

            add { }

            remove { }

        }

 

        public void DerivedCase1Event()

        {

            if (case1_event != null)

                case1_event(this, null);

        }

 

        public override void RaiseCase1Event()

        {

            if (case1_event != null)

                case1_event(this, null);

        }

    }

}

25. Use Exceptions to Report Method Contract Failures

Any method that cannot perform its stated actions should report that failure by throwing an exception. Do not use 'error codes' as these can be ignored and can pollute the normal flow of execution with constant error checks. Exceptions have one purpose only: to report failures. Because exceptions are class types and you can derive your own exception types, you can use exceptions to convey rich information about the failure.

Error return codes must be processed by the method caller. In contrast, thrown exceptions propagate up the call stack until a suitable catch clause is found. That gives developers the freedom to isolate error handling from error generation by many levels in the call stack. No error information is lost in this separation because of the richness of your exception classes.

Finally and most importantly, exceptions cannot be ignored. If a program does not contain a suitable catch clause, then a thrown exception terminates the application. You can't continue running after an unnoticed failure, something that would cause data corruption.

Using exceptions to report contract failures does not mean that any method that cannot do what you want must exit by throwing an exception. For example, consider File.Exists() and File.Open(): File.Open() throws an exception if a file is not found, however, File.Exists() does not throw exceptions at all, it just examines if a file exists and returns true or false.

How does this information affect your designs: You should create methods in your classes that enable users to test possible failure conditions before performing work. This practice lets developers program more defensively, and you can still throw exceptions if developers choose not to test conditions before calling methods.

class Item25

{

    public void DoNotPromoteThisPattern()

    {

        OrderManager om = new OrderManager();

        try

        {

            om.ProcessOrder(10);

        }

        catch (Exception ex)

        {

            Trace.WriteLine(ex.Message);

        }

    }

 

    public void PromoteThisPattern()

    {

        OrderManager om = new OrderManager();

        try

        {

            if (!om.TryProcessOrder(10))

            {

                Trace.WriteLine("Order is invalid");

            }

        }

        catch (Exception ex)

        {

            Trace.WriteLine(ex.Message);

        }

    }

}

 

namespace Item25NS

{

    /// <summary>

    /// This pattern requires you to write four methods: two public methods, and two private methods.

    /// The TryProcessOrder() method validates all input parameters and any internal object state

    /// necessary to perform the work. Then it calls the DoProcessOrder() method to perform the task.

    /// ProcessOrder() simply calls the DoProcessOrder() method and lets any failures generate exceptions.

    /// This idiom is used in .NET because there are performance implications involved in throwing

    /// exceptions, and developers may wish to avoid those costs by testing conditions before allowing

    /// methods to fail.

    /// </summary>

    class OrderManager

    {

        #region Public interface

        public void ProcessOrder(int nOrderID)

        {

            DoProcessOrder(nOrderID);

        }

 

        public bool TryProcessOrder(int nOrderID)

        {

            // Is the order valid

            if (!IsOrderValid(nOrderID)) return false;

 

            // We have a valid order. Process the order

            DoProcessOrder(nOrderID);

            return true;

        }

        #endregion

 

        #region Helpers

        /// <summary>

        /// Processes an order. Throws exceptions if it fails.

        /// </summary>

        private void DoProcessOrder(int nOrderID)

        {

            // Do we have a valid order ID

            if (nOrderID == -1)

                throw new InvalidOperationException("Received invalid order ID");

 

            // Continue processing order

            // ...

        }

 

        /// <summary>

        /// Checks that an order exists

        /// </summary>

        private bool IsOrderValid(int nOrderID)

        {

            // Do we have a valid order ID

            if (nOrderID == -1) return false;

 

            // Check order against database

            // ...

            return true;

        }

        #endregion

    }

}

26. Ensure that Properties Behave Like Data

When developers use properties they generally expect the following:

These expectations arise as a result of viewing properties as data. Properties are generally accessed in tight loops; consider for example using Length property on an array: for (int i = 0; i < myarray.Length; i++ ) ...

You would have a very poor performance if you had to count all elements in the array every time you accessed the array's length. To properly use properties:

class Item26

{

    public void TestAutoProperties()

    {

        // Using 'Automatically Implemented Properties'

        Point pt = new Point();

        pt.X = 10;

        pt.Y = 20;

 

        ReadOnlyPoint rpt = new ReadOnlyPoint(1, 2);

        int x = rpt.X;

        //rpt.X = 10;         // ERROR: The property or indexer 'ReadOnlyPoint.X' cannot be used in

                              // this context because the set accessor is inaccessible       

    }

 

    public void TestPropertyCaching()

    {

        // Using caching to imrpove property performance

        Averager<int> avg = new Averager<int>();

        avg.AddNumber(10);

        avg.AddNumber(20);

        double dAvg1 = avg.Average;         // Average calculated

        dAvg1 = avg.Average;                // Average obtained from cache

        avg.AddNumber(30);

        dAvg1 = avg.Average;                // Average calculated

    }

 

    public void TestPropertyValidation()

    {

        // Using validation in properties

        try

        {

            Person p = new Person();

            p.LastName = "";                // Throws an exception

        }

        catch (Exception ex)

        {

            Trace.WriteLine(ex.Message);

        }

    }

}

 

namespace Item26NS

    /// <summary>

    /// Use 'Automatically Implemented Properties' whenever possible. When a property is

    /// specified as an automatically implemented property, a hidden backing field is

    /// automatically available for the property, and the accessors are implemented to

    /// read from and write to that backing field.

    ///

    /// Because the backing field is inaccessible, it can be read and written only through

    /// the property accessors. This means that automatically implemented read-only or

    /// write-only properties do not make sense, and are disallowed. See Point class

    ///

    /// It is however possible to set the access level of each accessor differently. Thus,

    /// the effect of a read-only property with a private backing field can be mimicked. See

    /// ReadOnlyPoint class

    /// </summary>

    class Point

    {

        public int X { get; set; }      // automatically implemented

        public int Y { get; set; }      // automatically implemented

    }

    class ReadOnlyPoint

    {

        public ReadOnlyPoint(int x, int y) { X = x; Y = y; }

        public int X { get; private set; }

        public int Y { get; private set; }

    }

 

    /// <summary>

    /// 'Automatically Implemented Properties' do not support validation. In this case

    /// implement properties using an explicitly-specified backing store and add

    /// validation to each property setter. Validation code usually does not break

    /// any of the fundamental propery assumption listed at the top of this item.

    /// </summary>

    class Person

    {

        private string _strLastName;

        public string LastName

        {

            get { return _strLastName; }

            set

            {

                // Check we have a valid last name

                if (string.IsNullOrEmpty(value))

                    throw new ArgumentException("Last name cannot be null or empty");

                _strLastName = value;

            }

        }

    }

 

    /// <summary>

    /// Shows how to use caching to improve property performance. The 'Average' property

    /// is recalculated only if new values have been added to a list of numbers

    /// </summary>

    class Averager<T>

    {

        private List<T> lstNumbers = new List<T>();

        private double _dAverage;

        private bool _bCacheInvalid = true;

 

        // Add a number to the list of numbers and invalidate the cache

        public void AddNumber(T number)

        {

            lstNumbers.Add(number);

            _bCacheInvalid = true;

        }

 

        public double Average

        {

            get

            {

                // Compute only if cache is invalid

                if (_bCacheInvalid)

                {

                    _dAverage = lstNumbers.Average(num => Convert.ToDouble(num));

                    _bCacheInvalid = false;

                }

 

                // Return average

                return _dAverage;

            }

        }           

    }

 

    /// <summary>

    /// Shows that expensive property operation should be redesigned as public methods

    /// </summary>

    class Order

    {

        public int ID { get; set; }

        public int Value { get; set; }

    }

    class OrderManager_DoNotUse

    {

        public int OrderID { get; set; }

        public Order Order

        {

            get

            {

 

                return RetrieveOrderFromRemoteDatabase(OrderID);

            }

            set

            {

                SaveOrderInRemoteDatabase( value );

            }

        }

 

        private void SaveOrderInRemoteDatabase( Order Order)

        {

            // Save order to a remote database

        }

 

        private Order RetrieveOrderFromRemoteDatabase(int nOrderID)

        {

            // Get order from database

            return new Order();

        }

    }

 

    class OrderManager_Use

    {

        public int OrderID { get; set; }

        public void SaveOrderInRemoteDatabase(Order Order)

        {

            // Save order to a remote database

        }

 

        public Order RetrieveOrderFromRemoteDatabase()

        {

            // Get order from database

            return new Order();

        }

    }

}

27. Distinguish Between Inheritance and Composition

Recall that C# only supports public inheritance from a single class. Also recall that public inheritance is referred as 'IS A' while composition (or containment) is referred to as 'HAS A' Both inheritance (IS A) and composition (HAS A) provide ways to reuse implementation from another class. Inheritance is not always the best representation of a design. Inheritance creates the tightest coupling between two classes. The derived class contains all the members of the base class. And because the derived class IS A instance of the base class, an object of the derived class type can be substituted for an object of the base class at any time. Composition (or containment) on the other hand, allows the outer object to expose selected methods from the inner object, without such tight coupling of the public and protected interfaces.

Your class's interface is also insulated against future updates of the inner class. Using inheritance, upgrades to base types are automatically part of your class's interface. Using composition, you must explicitly modify your outer class in order to expose any new methods in the inner class. This constraint may be important if the inner class was created by a third party. Your user community can get newer versions of those components without getting an upgrade of your system.

See Item27NS1 namespace below for classes that use both inheritance and containment. Item27NS1.EmployeeWithComposition class has lost polymorphism because it does not derive from Person: You cannot substitute an instance of Item27NS1.EmployeeWithComposition when an instance of Person is expected. However, using interfaces you can 're-establish' polymorphism as shown in classes in Item27NS2 namespace

Finally, containment lets you change the inner class at runtime. You can examine various runtime conditions and create various inner classes. That requires you to have defined interfaces that your inner classes implement. It allows you to treat different inner classes polymorphically. See Item27NS3 namespace for an example.

From these discussions, you should strive to expand your set of design choices and use both composition and inheritance. When you create types that reuse implementation from other types, you should use composition. If your types model an IS A relationship in every way, inheritance is the better choice. Composition requires more work to expose the implementation from the inner objects, but the payoff is more control over the coupling between your type and the type whose implementation you wish to reuse. Using inheritance means that your derived type is a special case of the base class in every way.

class Item27

{

    /// <summary>

    /// Shows differences between inheritance and composition. EmployeeWithInheritance inherits

    /// all public methods of Person, while EmployeeWithComposition contains an instance of Person

    /// and selectively implements specific methods from Person

    /// </summary>

    public void TestCompositionVsInheritance()

    {

        // Base class

        Item27NS1.Person person = new Item27NS1.Person();

        person.FirstName = "Yazan";

 

        // Derived class

        Item27NS1.EmployeeWithInheritance empI = new Item27NS1.EmployeeWithInheritance();

        empI.DateOfEmployment = DateTime.Now;

        empI.FirstName = "Yazan";

        empI.LastName = "Diranieh";

        empI.DOB = DateTime.Now.AddYears(-30);

 

        // Class with composition (note that DOB is not available)

        Item27NS1.EmployeeWithComposition empC = new Item27NS1.EmployeeWithComposition();

        empC.DateOfEmployment = DateTime.Now;

        empC.FirstName = "Yazan";

        empC.LastName = "Diranieh";

    }

 

    /// <summary>

    /// Both Person and EmployeeWithContainment implement IPerson interface to 're-establish'

    /// polymorphism that was lost in the classes used in TestCompositionVsInheritance() method

    /// </summary>

    public void TestCompotionViaInterface()

    {

        // Create a Person instance

        Item27NS2.Person person = new Item27NS2.Person();

        person.DOB = DateTime.Now;

        person.FirstName = "Yazan";

        person.LastName = "Diranieh";

 

 

        // Create an EmployeeWithContainment instance

        Item27NS2.EmployeeWithContainment emp = new Item27NS2.EmployeeWithContainment();

        emp.DateOfEmployment = DateTime.Now;

        emp.FirstName = "Yazan";

        emp.LastName = "Diranieh";

        emp.DOB = DateTime.Now.AddYears(-30);

 

        // Note that PrcoessPerson accepts both 'emp' and 'person' instances as they both

        // implement the IPerson interface

        PrcoessPerson(person);

        PrcoessPerson(emp);

    }

    private void PrcoessPerson(Item27NS2.IPerson person)

    {

        Trace.WriteLine("FirstName: " + person.FirstName + Environment.NewLine +

                         "LastName: " + person.LastName + Environment.NewLine +

                         "DOB: " + person.DOB + Environment.NewLine);

    }

 

    /// <summary>

    /// Shows how the use interface allows a containing class to support different

    /// inner classes implementations at runtime

    /// </summary>

    public void TestCompositionRuntimeChanges()

    {

        try

        {

            // Uses Person1 implementation. Does not throw exception when FirstName is empty

            Item27NS3.EmployeeWithContainment emp1 = new Item27NS3.EmployeeWithContainment(1);

            emp1.FirstName = "";

        }

        catch (Exception ex)

        {

            Trace.WriteLine(ex.Message);

        }

 

        try

        {

            // Uses Person2 implementation. Throws an exception when FirstName is empty

            Item27NS3.EmployeeWithContainment emp = new MoreEffectiveCS.Design.Item27NS3.EmployeeWithContainment(2);

            emp.FirstName = "";

        }

        catch (Exception ex)

        {

            Trace.WriteLine(ex.Message);

        }

    }

}

 

namespace Item27NS1

{

    /// <summary>

    /// Base class that exposes a few public properties

    /// </summary>

    class Person

    {

        public string FirstName { get; set; }

        public string LastName { get; set; }

        public DateTime DOB { get; set; }

    }

 

    /// <summary>

    /// Derived class that inherits publicly from Person. EmployeeWithInheritance inherits

    /// all public members (properties, fields, methods, events, etc.) of the base class

    /// </summary>

    class EmployeeWithInheritance : Person

    {

        public DateTime DateOfEmployment { get; set;}

    }

 

    /// <summary>

    /// A class that contains (has a) Person object rather than derive from Person.

    /// With containment (i.e., composition) you can selectively choose which, if any,

    /// of the public members available in the inner class are exposed as part of the

    /// containing (outer) class. Note that public members of the contained class (Person)

    /// are implemented by delegating to the contained instance of Person.

    ///

    /// </summary>

    class EmployeeWithComposition

    {

        // Contained class. Could also be passed via a constructor

        private Person _person = new Person();

 

        // Public interface for EmployeeWithComposition

        public DateTime DateOfEmployment { get; set; }

 

        // The following two properties are delegated to the contained object

        public string FirstName

        {

            get { return _person.FirstName; }

            set { _person.FirstName = value; }

        }

 

        public string LastName

        {

            get { return _person.LastName; }

            set { _person.LastName = value; }

        }

    }

}

 

namespace Item27NS2

{

    /// <summary>

    /// Interface IPerson is supported by two Person and EmployeeWithContainment classes.

    /// EmployeeWithContainment delegats all its IPerson methods to its contained Person

    /// class. EmployeeWithContainment cannot be used by a method that expects a Person

    /// object, but both EmployeeWithContainment and Person object can be used by methods

    /// that expect an IPerson object. Note that the concept of refactoring methods into

    /// interfaces makes it easier to create outer classes that aggregate more than one

    /// inner type. For example, you can create another interface IEmployee and have

    /// EmployeeWithContainment implement IPerson and IEmployee

    /// </summary>

    public interface IPerson

    {

        string FirstName { get; set; }

        string LastName { get; set; }

        DateTime DOB { get; set; }

    }

 

    /// <summary>

    /// Implements IPerson

    /// </summary>

    public class Person : IPerson

    {

        #region IPerson Members

        public string FirstName {get; set;}

        public string LastName  {get; set;}

        public DateTime DOB     {get; set;}

        #endregion

    }

 

    /// <summary>

    /// Implement IPerson by delegating to an inner Person object

    /// </summary>

    public class EmployeeWithContainment : IPerson

    {

        // Contained class. Could also be passed via a constructor

        private Person _person = new Person();

 

        // Publi interface

        public DateTime DateOfEmployment { get; set; }

 

        #region IPerson Members

        public string FirstName

        {

            get { return _person.FirstName; }

            set { _person.FirstName = value; }

        }

 

        public string LastName

        {

            get { return _person.LastName; }

            set { _person.LastName = value; }

        }

 

        public DateTime DOB

        {

            get { return _person.DOB; }

            set { _person.DOB = value; }

        }

 

        #endregion

    }

}

 

namespace Item27NS3

{

    interface IPerson

    {

        string FirstName { get; set; }

        string LastName { get; set; }

        DateTime DOB { get; set; }

    }

 

    /// <summary>

    /// Implements IPerson

    /// </summary>

    class Person1 : IPerson

    {

        #region IPerson Members

        public string FirstName { get; set; }

        public string LastName { get; set; }

        public DateTime DOB { get; set; }

        #endregion

    }

 

    /// <summary>

    /// Same as Person1 except that it now adds validations

    /// </summary>

    class Person2 : IPerson

    {

        // Backing stores for IPerson properties

        private string _strFirstName = string.Empty;

        private string _strLastName = string.Empty;

 

        #region IPerson Members

        public string FirstName

        {

            get { return _strFirstName; }

            set

            {

                if (string.IsNullOrEmpty( value ))

                    throw new ArgumentException("FirstName cannot be null or empty");

                _strFirstName = value;

            }

        }

 

        public string LastName

        {

            get { return _strLastName; }

            set

            {

                if (string.IsNullOrEmpty( value ))

                    throw new ArgumentException("LastName cannot be null or empty");

                _strLastName = value;

            }

        }

        public DateTime DOB { get; set; }

        #endregion

    }

  

    /// <summary>

    /// Implement IPerson by delegating to an inner Person1 object or Person2 object,

    /// based on a version number that is passed at runtime. This allows EmployeeWithContainment

    /// class to change its runtime behavior based on which version is required

    /// </summary>

    class EmployeeWithContainment : IPerson

    {

        // Contained class. Could also be passed via a constructor

        private Person1 _person1 = new Person1();

        private Person2 _person2 = new Person2();

        private int _version = 0;

        public EmployeeWithContainment(int version)

        {

            _version = version;

        }

        // Publi interface

        public DateTime DateOfEmployment { get; set; }

 

        #region IPerson Members

        public string FirstName

        {

            get  { return (_version == 1) ? _person1.FirstName : _person2.FirstName; }

            set

            {

                if (_version == 1)

                    _person1.FirstName = value;

                else

                    _person2.FirstName = value;

            }

        }

 

        public string LastName

        {

            get { return (_version == 1) ? _person1.LastName : _person2.LastName; }

            set

            {

                if (_version == 1)

                    _person1.LastName = value;

                else

                    _person2.LastName = value;

            }

        }

        public DateTime DOB

        {

            get { return (_version == 1) ? _person1.DOB : _person2.DOB; }

            set

            {

                if (_version == 1)

                    _person1.DOB = value;

                else

                    _person2.DOB = value;

            }

        }

        #endregion 

    }       

}

C# 3.0 Features

28. Augment Minimal Interface Contracts With Extension Methods

Recall that extension methods are used to extend existing types and constructed types with additional methods. You can define an interface with minimal capabilities and then create a set of extension methods defined on that interface to extend its capabilities. In particular, you can add behavior instead of just defining an API.

Syntactically, you create a static class with static methods that have a specific signature: the first parameter of any extension method must be the this keyword, which identifies the type on which the extension method will appear. System.Linq.Enumerable class provides a great example of this technique. This class contains more than 50 extension methods defined on IEnumerable<T>. Those methods range from Where to OrderBy to ThenBy to GroupInto. Defining these as extension methods on IEnumerable<T> provides great advantages. First, none of these capabilities requires modifications to any class that already implements IEnumerable<T>. No additional responsibilities have been added for classes that implement IEnumerable<T>. However, Implementers still need define only GetEnumerator(), and IEnumerator<T> still need define only Current, MoveNext(), and Reset(). Yet by creating extension methods, the C# compiler ensures that all collections now support query operations.

You can follow the same pattern yourself. For example, IComparable<T> follows a pattern from the days of C. If left < right, then left.CompareTo(right) returns a value less than 0. If left > right, then left.CompareT (right) returns a value greater than 0.  When left and right are equivalent, left.CompareTo(right) returns 0. This pattern has been used so often that many of us have it memorized, but that doesn't make it very approachable. It would be much more readable to write something like left.LessThan(right) or left.GreaterThanEqual(right). That's easy to do with extension methods. See method TestSimpleExtensionMethod().

You should also follow the same pattern as defined in Item28NS with interfaces you've created in your applications. Rather than define rich interfaces, use the interface to define the minimal functionality necessary to satisfy the requirements. ANY CONVENIENCE METHODS THAT CAN BE BUILT ON THAT MINIMAL INTERFACE SHOULD BE CREATED USING EXTENSION METHODS. Compared with richer interface contracts, using extension methods enables implementers to write fewer methods and still provide a richer interface to client code.

class Item28

{

    public void TestSimpleExtensionMethod()

    {

        Person p1 = new Person( new DateTime(1990,1,1));

        Person p2 = new Person(new DateTime(2000, 1, 1));

 

        bool bLessThan = p1.LessThan(p2);

        bool bGreaterThan = p1.GreaterThan(p2);           

    }

}

 

namespace Item28NS

{

    /// <summary>

    /// Similar in purpose to System.Linq.Enumerable. Provides a set of extension methods

    /// on IComparable<T>. Note that the class is static, meaning that all its members

    /// are also static

    /// </summary>

    static class Comparable

    {

        public static bool LessThan<T>(this T left, T right) where T : IComparable<T>

        {

            return (left.CompareTo(right) < 0);

        }

 

        public static bool GreaterThan<T>(this T left, T right) where T : IComparable<T>

        {

            return (left.CompareTo(right) > 0);

        }

 

        public static bool GreaterThanOrEqual<T>(this T left, T right) where T : IComparable<T>

        {

            return (left.CompareTo(right) >= 0);

        }

 

        public static bool LessThanOrEqual<T>(this T left, T right) where T : IComparable<T>

        {

            return (left.CompareTo(right) <= 0);

        }

    }

 

    /// <summary>

    /// A simple class that implements IComparable<T> on date of birth. In fact, every class that

    /// implements IComparable<T> now appears to include these additional methods if the proper

    /// using declaration is in scope. Implementers still need only create one method (CompareTo),

    /// and the client code can use other, easier-to-read signatures.

    ///

    /// </summary>

    public class Person : IComparable<Person>

    {

        public DateTime DOB { get; set; }

        public Person(DateTime dob)

        {

            DOB = dob;

        }

 

        #region IComparable<Person> Members

        public int CompareTo(Person other)

        {

            return DateTime.Compare(DOB, other.DOB);

        }

        #endregion

    }

}

29. Enhance Constructed Types with Extension Methods

First a quick definition. A constructed type is a generic type with at least one type argument. For example, given the generic type List<T>, List<int>, List<string>, List<MyType>, etc are all constructed types. An open constructed type is created when at least one type argument is left unspecified, while a closed constructed type is created by specifying all type arguments. For example given generic type LinkedList<K,T>:

LinkedList<int, T> lst1;         // lst1 is an open constructed type
LinkedList<int, long> lst2;      // lst2 is a closed constructed type

Item 28 discussed System.Linq.Enumerable class and how it extends IEnumerable<T> with many common methods on sequences. In addition, System.Linq.Enumerable contains a number of methods that are implemented specifically for particular 'constructed types' that implement IEnumerable<T>. For example, several numeric methods are implemented on numeric sequences (IEnumerable<int>, IEnumerable<double>, IEnumerable<long>, and IEnumerable<float>). Here are a few of the extension methods implemented specifically for IEnumerable<int>:

public class Enumerable
{
    public static int Average(this IEnumerable<int> sequence);
    public static int Max(this IEnumerable<int> sequence);
    public static int Min(this IEnumerable<int> sequence);
    public static int Sum(this IEnumerable<int> sequence);

    // other methods ...
}


Once you recognize the pattern, you can see many ways you could implement the same kind of extensions for your own constructed types. If you didn't have extension methods, you could achieve a similar effect by deriving a new type from the constructed generic type you used. See notes for Item29NS_DoNotUse below:

class Item29

{

    public void TestMethodExtensions()

    {

        // Create a collection customers

        List<Customer> lstCustomers = new List<Customer>();

        lstCustomers.Add(new Customer(1, "x", "y"));

        lstCustomers.Add(new Customer(2, "a", "b"));

        lstCustomers.Add(new Customer(3, "g", "h"));

 

        // Now how extension methods are available on 'lstCustomers' constructed type

        lstCustomers.SendCustomerEmail("this is a test message");

        lstCustomers.PrintAllCustomerDetails();

      }

}

 

namespace Item29NS

{

    class Customer

    {

        public int CustomerID {get; set;}

        public string FirstName { get; set; }

        public string LastName { get; set; }

 

        public Customer(int id, string fn, string ln)

        {

            CustomerID = id;

            FirstName = fn;

            LastName = ln;

        }

        public void AddOrder()

        {

            // Method to assocaite order with this customer

        }

    }

 

    static class CustomerExtensions

    {

        public static void SendCustomerEmail(this IEnumerable<Customer> customers, string strMessage)

        {

            Trace.WriteLine("Implement SendCustomerEmail to send message to all customers");

        }

 

        public static void PrintAllCustomerDetails(this IEnumerable<Customer> customers)

        {

            Trace.WriteLine("PrintAllCustomerDetails to print all customer details");

        }

    }

}

 

namespace Item29NS_DoNotUse

{

    /// <summary>

    /// The extension methods in class Item29NS.CustomerExtensions use IEnumerable<Customer> as the parameter,

    /// but the methods added to CustomerList class below are based on List<Customer>. They mandate a particular

    /// storage model. For that reason, they can't be composed as a set of iterator methods

    /// </summary>

    class CustomerList : List<Customer>

    {

        public void SendCustomerEmail(string strMessage)

        {

            Trace.WriteLine("Implement SendCustomerEmail to send message to all customers");

        }

 

        public void PrintAllCustomerDetails()

        {

            Trace.WriteLine("PrintAllCustomerDetails to print all customer details");

        }

    }

}

30. Prefer Implicitly Typed Local Variables

There are times when it's better to use implicitly typed variables, because the compiler will pick a better type than you will. Recall that the compiler examines the compile-time type and infers the type of the local variable based on those declarations. At other times, however, overusing var only decreases the readability of your code. Even worse, using implicitly typed variables can lead to subtle conversion bugs.

Many times, the type of a local variable is clear from its initialization statement:

var foo = new MyType();

However, in some cases, the return type might not always be clear from the method name:

var foo = someObject.DoSomeWork(anotherParameter);

Therefore, introducing var for a variable returned from some method is one of the ways that the use of var can be confusing.

When you work with built-in numeric types, using implicitly typed variables can lead to conversion bugs because many implicit conversions are available on numeric types. However by explicitly declaring the types of all numeric variables, you retain some control over the types used, and you help the compiler warn you about possible dangerous conversions.

Variables declared with var are not dynamic but instead are implicitly declared with the type of the right side of the assignment. You are not telling the compiler which type you're creating; the compiler declares the type for you. When the type you want is not the same as the type the compiler would pick, you introduce problems in your code. Sometimes, though, the compiler may be smarter than you are. See TestEnumerableAndQueryable() method below.

class Item30

{

    /// <summary>

    /// Consider q1 and q2 queries below.

    ///

    /// Because the query is running against a database, it's actually in IQueryable<string>.

    /// However, by strongly declaring the return value, you've lost that information. IQueryable<T>

    /// derives from IEnumerable<T>, so the compiler does not even warn you about this assignment

    /// which has a serious performance problems. Now when the second portion of the query is

    /// compiled, Enumerable.Where will be used, rather than Queryable.Where. That has a large

    /// negative implication for performance. In Item38 you will note that IQueryable composes

    /// multiple query expression trees into a single operation that can be executed at once,
   
/// often at the remote server where the data is located. In this instance the second portion
   
/// of the query (the where clause) sees the source as an IEnumerable<string>. That change is
   
/// significant, because only the first part of the query is built on the remote machine. The

    /// entire list of customer names will be returned from the source. The second statement (the
   
/// where clause) locally examines the entire list of customer contact names and returns only

    /// those matching the search string.

    ///

    /// Now consider q3 and q4 queries below.

    ///

    /// q3 is an IQueryable<Employee>. The compiler infers the return type because of the source

    /// of the query. The second statement composes the query, adding the Where clause to the query,

    /// and holds a new, more complete expression tree. The actual data is retrieved only when the

    /// caller examines the query. The expression to filter the query gets passed to the data source,

    /// and the result sequence contains only those employees that match the filter. Any network
   
/// traffic is reduced, and the query is more efficient. This miraculous change is that q3 is
   
/// now declared (by the compiler) as IQueryable<Employee> instead of IEnumerable<Employee>

    ///

    /// To summarize: it's best to declare local variables using var unless developers (including

    /// you, in the future) need to see the declared type to understand the code. However, explicitly

    /// declare all numeric types (int, float, double, and others) rather than use var declarations.

    /// </summary>

    public void TestEnumerableAndQueryable()

    {

        // Create a context to the AdvanetureWorks database

        AdventureWorksLINQDataContext ctxt = new AdventureWorksLINQDataContext();

 

        // IEnumerable query

        IEnumerable<Employee> q1 = from e in ctxt.Employees select e;

        var q2 = q1.Where((Employee e) => e.Gender == 'M');

        foreach (var e in q2)

            Trace.WriteLine("ID: " + e.EmployeeID + ", DOB: " + e.BirthDate);

 

        // IQueryable query

        Trace.WriteLine("");

        var q3 = from e in ctxt.Employees  select e;

        var q4 = q3.Where((Employee e) => e.Gender == 'M');

        foreach (var e in q4)

            Trace.WriteLine("ID: " + e.EmployeeID + ", DOB: " + e.BirthDate);

    } 

}

31 Limit Type Scope by Using Anonymous Types

You should use anonymous types whenever you need simple data containers that store interim results. Anonymous types are scoped inside the method where they are declared. Using an anonymous type clearly shows other developers that a particular type is scoped inside that single method.

Anonymous types save you quite a bit of work and help you gain features because the compiler can generate some code you can't. Consider the following anonymous object initializer:

var point = new {X=1, Y=2};

The declaration above implies the following:

You've told the compiler to write something like this for you:

internal sealed class __Anonymous
{
    private readonly int x;
    public int X
    {
        get { return X; }
    }
    private readonly int y;
    public int Y
    {
        get { return y; }
    }
    public __Anonymous(int xParm, int yParm)
    {
        x = xParm;
        y = yParm;
    }
}

It is better to let the compiler write this rather than manually code it for the following reasons:

  1. The amount of code to maintain is minimized.
  2. The compiler generates the same definition for these repetitive tasks thus eliminating human errors.
  3. There is less runtime cost for anonymous types. Whenever you create the same anonymous type, the compiler reuses the same anonymous type as before.

Also note that anonymous types support IEquatable<T> and nothing else. So you can assume the existence only of the System.Object public members and the IEquatable<T> members.

The obvious drawback of using anonymous types is that you don't know the name of the type. Because you don't name the type, you can't use an anonymous type as a parameter to a method or as its return value. However, if you mix in generic methods that contain function parameters, you can create methods that work with anonymous types. The scope of an anonymous type is limited to the method where it is defined. Using generic methods and lambdas means that you can define any necessary transformations on those anonymous types within the scope of the method where the anonymous type is defined. See TestBasicAnonymousType() method below.

class Item31

{

    public void TestBasicAnonymousType()

    {

        // Error: Cannot assign <null> to anonymous type property

        //var Employee = new { ID = 1, Name= null};

 

        // The use of a generic method that has a function parameter allows you to pass

        // in anonymous types

        var point = new { X = 1, Y = 2 };

        var point2 = Transform( point, (pt) => new {X=pt.X * 10,  Y=pt.Y * 10});

    }

    private T Transform<T>(T element, Func<T, T> transformFunc)

    {

        return transformFunc(element);

    }

}

32. Create Composable APIs for External Components

Composable methods relate to methods on objects that act as input parameters. Specifically composable methods are member methods of one of the input parameters, and they return a
result that is composed from the transformation involved in the method
. In the code below, compare methods in NonComposableMethods class with the much better methods in ComposableMethods.

See BadExtensionMethods which illustrate some of the basic scenarios where extension methods are abused

Extension methods are a great way to massage the signature of an API so that it can be composed into complicated expressions. However, when you create extension methods to change the composability of an API, you need to ensure that the API doesn't hide errors nor change the performance metrics of an implied API.

class Item32

{

    /// <summary>

    /// Tests composable vs. non-composable methods. End results are the same but composable

    /// methods can be easily enhanced without affecting overall method semantics

    /// </summary>

    public void TestComposableMethods()

    {

        // Read CSV file. Content is:

        //   1,2,3,4,5
       
//   6,7,8,9,10
       
//   11,12,999

        StreamReader reader = new StreamReader(@"D:\Projects\MoreEffectiveCS\MoreEffectiveCS\C#3\Item31Input.txt");

 

        // Parse CSV file using a non-composable method

        NonComposableMethods obNonComp = new NonComposableMethods();

        List<List<int>> lstLines1 = obNonComp.CSVParser(reader);

        PrintResults(lstLines1);

 

        // Parse CSV file using a composable method

        ComposableMethods obComp = new ComposableMethods();

        reader.BaseStream.Seek(0, SeekOrigin.Begin);

        IEnumerable<IEnumerable<int>> lstLines2 = obComp.SimpleCSVParser(reader);

        PrintResults(lstLines2);

 

        // Parse CSV file using a composable method that detects invalid input

        reader.BaseStream.Seek(0, SeekOrigin.Begin);

        IEnumerable<IEnumerable<int>> lstLines3 = obComp.CSVParserWithDetect(reader);

        PrintResults(lstLines3);

    }

 

    /// <summary>

    /// Illustrates a few bad examples of extension methods

    /// </summary>

    public void TestBadExtentions()

    {

        // GetStringLength() is an extension method that works with nulls. BAD!

        string name = null;

        name.GetStringLength();

 

        // Inefficient extension method

        List<int> lst = new List<int>{1,2,3,4};

        List<int> lstReversed = lst.InefficientReverse().ToList();

 

        // Using an array to call an AddRange extension method

        string[] numbers = { "one", "two", "three" };

        string[] range = { "four", "five"};

        numbers.AddRange(range); 

    }

 

    private void PrintResults(IEnumerable<IEnumerable<int>> lines)

    {

        foreach (IEnumerable<int> a in lines)

        {

            foreach (int n in a)

                Trace.Write(n + ",");

            Trace.WriteLine("");

        }

    }

 

    private void PrintResults(List<List<int>> lines)

    {

        foreach (List<int> a in lines)

        {

            foreach (int n in a)

                Trace.Write(n + ",");

            Trace.WriteLine("");

        }

    }

}

 

namespace Item32NS

{

    /// <summary>

    /// A class illustrating non-composable methods

    /// </summary>

    public class NonComposableMethods

    { 

        /// <summary>

        /// CSVParser reads a CSV file of numeric data and returns a list of arrays, where each array

        /// contains the values in one line

        ///

        /// This implementation works as requried but does not support composition.  Suppose the files

        /// were very large and contained marker values that would indicate when you could stop reading

        /// the file. To modify this method for new requirements, you'd need to add parameters, add logic

        /// to support changes, and increase the overall complexity of the method. Because you've chosen

        /// an imperative model, whenever any changes are needed you must change the description of how

        /// the method works. WHAT'S NEEDED IS TO MODITY THE API SIGNATURES TO PROVIDE COMPOSABILITY OF

        /// THE ACTIONS, SOMETHING THAT WILL ALLOW CALLERS TO MODIFY THE BEHAVIOR BY USING DIFFERENT

        /// EXPRESSIONS.

        /// </summary>

        public List<List<int>> CSVParser(TextReader src)

        {

            // Required variables

            List<List<int>> lstLinesAsNumbers = new List<List<int>>();

            string strCurrentLineAsCSVLine = string.Empty;

            string[] astrCurrentLineAsArray;               

            int nDataValue = 0;

 

            // Read all lines until we get a null

            while ((strCurrentLineAsCSVLine = src.ReadLine()) != null)

            {

                // Split current line into an array of strings

                astrCurrentLineAsArray = strCurrentLineAsCSVLine.Split(new char[] { ',' });

 

                // Now parse into numbers

                List<int> lstCurrentLine = new List<int>();

                foreach (var value in astrCurrentLineAsArray)

                {

                    nDataValue = 0;

                    int.TryParse(value, out nDataValue);

                    lstCurrentLine.Add(nDataValue);

                }

                lstLinesAsNumbers.Add(lstCurrentLine);

            }

 

            return lstLinesAsNumbers;

        } 

    }

  

    /// <summary>

    /// Contains composable methods for parsing lines.

    /// Note that even though the method signatures have changed (compared to NonComposableMethods.CSVParser),

    /// the underlying semantics have not. That's an important consideration when you create extension methods.

    /// Be sure not to change the caller's assumption about the behavior of the objects involved in the extension

    /// method.

    /// </summary>

    public class ComposableMethods

    {

        /// <summary>

        /// Same as NonComposableMethods.CSVParser except that SimpleCSVParser is now

        /// composable

        /// </summary>

        public IEnumerable<IEnumerable<int>> SimpleCSVParser(TextReader src)

        {

            var lines = from line in src.ReadLines() select line.ParseLine(0);

            return lines;

        }

 

        /// <summary>

        /// Same as SimpleCSVParser except that it now it reads until it finds an invalid

        /// value which is indicated by 999. All this is possible because we've used extension

        /// methods to modify the API signature into a composable form

        /// </summary>

        public IEnumerable<IEnumerable<int>> CSVParserWithDetect(TextReader src)

        {

            var lines = (from line in src.ReadLines()

                         select line.ParseLine(0)).

                         TakeWhile((LineOfValues) => !LineOfValues.Contains(999));

            return lines;

        }

    }

 

    /// <summary>

    /// Extension methods to allow composability of a CSV parser

    /// </summary>

    public static class ParseExtensions

    { 

        /// <summary>

        /// Parsing a string to a nullable integer

        /// </summary>

        public static int? DefaultParse(this string value)

        {

            int answer;

            int? n = int.TryParse(value, out answer) ? answer : default(int?);

            return n;

        }

 

        /// <summary>

        /// Parsing a string to an integer and returning a default value if parsing fails

        /// </summary>

        public static int DefaultParse(this string value, int defaultValue)

        {

            int answer;

            int n = int.TryParse(value, out answer) ? answer : defaultValue;

            return n;

        }

 

        /// <summary>

        /// Parsing a single line into an array of ints

        /// </summary>

        public static IEnumerable<int> ParseLine(this string line, int defaultValue)

        {

            string[] fields = line.Split(',');

            foreach (string field in fields)

                yield return (field.DefaultParse(defaultValue));

        }

 

        /// <summary>

        /// Parsing a single line into an array of nullable ints

        /// </summary>

        public static IEnumerable<int?> ParseLine(this string line)

        {

            string[] fields = line.Split(',');

            foreach (string field in fields)

                yield return (field.DefaultParse());

        }

 

        /// <summary>

        /// Read text line in successsion

        /// </summary>

        public static IEnumerable<string> ReadLines(this TextReader reader)

        {

            string line = string.Empty;

            while ((line = reader.ReadLine()) != null)

                yield return line;

        }

    }

 

    /// <summary>

    /// Illustrates some of the basic scenarios where extension methods are abuded

    /// </summary>

    public static class BadExtensionMethods

    {

        /// <summary>

        /// Instance methods cannot be called using a null reference, because the .NET runtime will

        /// throw a null reference exception instead of calling your routine. Therefore, never write

        /// extension methods designed to work with null objects

        /// </summary>

        public static int GetStringLength(this string input)

        {

            if (input == null)

                return -1;

            else

                return input.Length;

        }

 

        /// <summary>

        /// Do not create extension methods that have significantly worse performance than users expect

        /// as it creates a new copy which slows performance

        /// </summary>

        public static IEnumerable<T> InefficientReverse<T>(this IEnumerable<T> sequence)

        {

            IList<T> temp = new List<T>(sequence);

            return temp.Reverse();

        }

 

        // Avoid creating extension methods that have a high likelihood of failure, which often occurs when

        // you extend the .NET collection interfaces. Examine this method, which extends ICollection<T>

        // by providing support for AddRange(). However, if you use an array to call this routine, the

        // compiler throws an exception. Most types that implement ICollection<T> and support Add already

        // have their own version of AddRange included. You've added no capabilities but have increased

        // the likelihood that someone calling your new extension method will get frustrated by exceptions.            

        public static void AddRange<T>(this ICollection<T> coll, IEnumerable<T> range)

        {

            foreach (T item in range)

                coll.Add(item);

        }

    }

}

33. Avoid Modifying Bound Variables

Note on closures: A closure is a function that can refer to and alter the values of variables defined in its declaring scope. In C# closures correspond to anonymous delegates:

int x = 1;
Action<int> Add = new Action<T>(delegate (int y)
{
    x = x + y;
}


Here the variable x can be accessed and modified inside the anonymous delegate. To begin, study BoundVariables.ModifyBoundVariable() method below.

The C# compiler converts your queries and lambda expressions into static delegates, or instance delegates, or closures. It chooses which one to create based on the code inside the lambda. Which path the compiler takes depends on the body of the lambda. This has important implications for your code. As a result, modifying the bound variables between queries can introduce errors caused by the interaction of deferred execution and the way the compiler implements closures. Therefore, you should always avoid modifying bound variables that have been captured by a closure.

class Item33

{

    public void ShowEffectOfModifyingBoundVariable()

    {

        BoundVariables bv = new BoundVariables();

        bv.ModifyBoundVariable();

    }

}

 

namespace Item33NS

{

    class BoundVariables

    {

        public void ModifyBoundVariable()

        {

            // Create a sequence of 30 consecutive integers starting at 0, i.e., generate

            // 1, 2, ..., 29, 30

            int nIndex = 0;        

            IEnumerable<int> sequence = Utilities.Generate<int>(30, () => nIndex++);

 

            // The following simple assignment creates a very subtle bug: nIndex is modified AFTER

            // it has been placed in closure (Generate lambda expression above) but BEFORE the

            // query has been executed. This is due to interaction of 'deferred execution' and the

            // way the compiler implements closures

            nIndex = 20;   

 

            // Now iterate and display sequence. Rather the printing 1, 30, the iteration prints

            // 20 to 50!!

            foreach (int n in sequence)

                Trace.WriteLine(n);

            Trace.WriteLine("Done");

        }

    }

 

    /// <summary>

    /// Utilities class used in this item

    /// </summary>

    public static class Utilities

    {

        /// <summary>

        /// Generates a sequence of numbers containing 'count' items using the supplied

        /// 'generator' function. Note the use of 'nIndex' variable

        /// </summary>

        public static IEnumerable<T> Generate<T>(int count, Func<T> generator)

        {

            int i = 0;

            while (i++ < count)

                yield return generator();

        }

    }

 

    /// <summary>

    /// This class illustrates the case when a Lambda expression is implemented as a static delegate.

    /// Here the body of the lambda expression does not access any instance variables nor local variables.

    /// The lambda expression accesses only its parameters. Therefore, the C# compiler creates a static

    /// method for the target of the delegate. That's the simplest path the compiler can take. The compiler

    /// generates a private static method and corresponding delegate definition whenever the expression to

    /// be enclosed can be implemented in a private static method. That includes simple expressions such

    /// as the example here or a method that accesses any static class variables

    /// </summary>

    class LambdaExpressionAsStaticDelegate

    {

        // Sample method

        public void MyFunction()

        {

            int[] numbers = new int[] { 1, 2, 3, 4, 5 };

            IEnumerable<int> sequence = from n in numbers select n * 2;               

        }

 

        // Method generated by compiler for MyFunction method

        public void MyFunction_CompilerVersion()

        {

            int[] numbers = new int[] { 1, 2, 3, 4, 5 };

            if (HiddenDelegateDefinition == null)

                HiddenDelegateDefinition = new Func<int, int>(HiddenFunc);

 

            IEnumerable<int> sequence = numbers.Select<int, int>(HiddenDelegateDefinition);

        }

        private static int HiddenFunc(int n)

        {

            return (n * n);

        }

        private static Func<int, int> HiddenDelegateDefinition = null;

    }

 

    /// <summary>

    /// This class illustates the case when a Lambda expression is implemented as an instance

    /// delegate. In this example, the lambda expression requires access to instance variables

    /// but not to any local variables.

    ///

    /// Whenever the code inside your lambda expression accesses member variables for your object

    /// instances, the compiler generates an instance method representing the code in your lambda

    /// expression. There's nothing magical going on here

    ///

    /// </summary>

    class LambdaExpressionAsInstanceDelegate

    {

        private readonly int modulus;

        public LambdaExpressionAsInstanceDelegate(int mod)

        {

            modulus = mod;

        }

 

        // Sample method that accesses instance variables

        public IEnumerable<int> MyFunction(IEnumerable<int> sequence)

        {

            return from n in sequence where (n % modulus == 0) select n * n;

        }

 

        // Methods generated by compiler for MyFunction method

        public IEnumerable<int> MyFunction_CompilerVersion(IEnumerable<int> sequence)

        {

            return sequence.Where<int>(new Func<int, bool>(this.WhereClause)).Select<int, int>(SelectClause);

        }

        private bool WhereClause(int n) { return ((n % this.modulus) == 0); }           

        private static int SelectClause(int n) { return (n * n); }

    }

 

    /// <summary>

    /// This class illustates the case when a Lambda expression is implemented as a closure

    ///

    /// The compiler does quite a bit more work if any of the code in your lambda expressions

    /// accesses local variables or accesses parameters to methods. Here, you need a closure.

    /// The compiler generates a private nested class to implement the closure for your local

    /// variables. The local variable must be passed to the delegate that implements the body

    /// of the lambda expression. In addition, any changes to that local variable performed by

    /// the lambda expression must be visible in the outer scope.

    ///

    /// To create the closure, the compiler creates a nested class to implement the behavior you

    /// need

    /// </summary>

    class LambdaExpressionAsClosure

    {

        private readonly int modulus;

        public LambdaExpressionAsClosure(int mod)

        {

            modulus = mod;

        }

 

        // Sample method that accesses instance variables

        public IEnumerable<int> MyFunction(IEnumerable<int> sequence)

        {

            int numValues = 0;

            return from n in sequence where (n % modulus == 0) select n * n / ++numValues;

        }

 

        // Methods generated by compiler for MyFunction method

        public IEnumerable<int> FindValues(IEnumerable<int> sequence)

        {

            Closure c = new Closure();

            c.outer = this;

            c.numValues = 0;

            return sequence.Where<int>(new Func<int, bool>(this.WhereClause))

                            .Select<int, int>(new Func<int, int>(c.SelectClause));

        }

 

        private bool WhereClause(int n)

        {

            return ((n % this.modulus) == 0);

        }

 

        private sealed class Closure

        {

            public LambdaExpressionAsClosure outer;

            public int numValues;

 

            public int SelectClause(int n)

            {

                return ((n * n) / ++this.numValues);

            }

        }

    }

}

34. Define Local Functions on Anonymous Types

Many believe that you can't properly develop with anonymous types because they can't be used in more than one method. That's not true. You can write generic methods that use anonymous types. Anonymous types are lightweight types that simply contain read and write properties that usually hold simple values. You will build many of your algorithms around these simple types. You can manipulate anonymous types using lambda expressions and generic methods. Just as you can create private nested classes to limit the scope of types, you can exploit the fact that the scope of an anonymous type is limited to a given method. See TestMethodWithAnonymousType() and TestMethodWithAnonymousType2() methods below.

class Item34

{

    public void TestMethodWithAnonymousType()

    {

        // Define a sequence of numbers

        List<int> numbers = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

 

        // Query to select even numbers. Returns an anonymous type

        var result = from n in numbers where (n % 2 == 0) select new { Number = n };

 

        // The following uses an anonymous type - indicated by 'new {Number = 4 }' statement -

        // as an argument to a function

        result = from n in FindValue( result, new {Number = 4 }) select n;

    }

 

    /// <summary>

    ///

    /// Note that query sequence uses the 'let' clause. Sometimes it is useful to store the result

    /// of a sub-expression in order to use it in subsequent expressions. The 'let' keyword creates

    /// a new range variable and initializes it with the result of the expression you supply. Once

    /// initialized with a value, the range variable cannot be used to store another value. However,

    /// if the range variable holds a queryable type, it can be queried.

    ///

    /// Take a look at the 'sequence' query:

    /// The query ends in the TakeWhile() method, which has this signature:

    ///     public static IEnumerable<TSource> TakeWhile<TSource>(this IEnumerable<TSource> source,

    ///                                                           Func<TSource, bool> predicate);

    ///    

    /// Notice that the signature of TakeWhile returns an IEnumerable<T> and has an IEnumerable<T>

    /// parameter. In our simple example, T stands in for an anonymous type representing an X,Y

    /// pair. Func<T, bool> represents a function that takes a T as its parameter.

    ///

    /// This technique gives you the pathway to creating large libraries and code that works with

    /// anonymous types. The following code creates an anonymous type and then processes that type in

    /// many generic methods

    /// </summary>

    public void TestMethodWithAnonymousType2()

    {

        // Note that TakeWhile operates on an anonymous types

        Random randomNumbers = new Random();

        var sequence = (from x in Item33NS.Utilities.Generate(100,() => randomNumbers.NextDouble() * 100)

                        let y = x / 100

                        select new { x, y }).TakeWhile( point => point.x < 75);

 

        var scaled = from p in sequence select new {x = p.x * 5, y = p.y * 5};

 

        var translated = from p in scaled select new { x = p.x - 20, y = p.y - 20};

 

        var distances = from p in translated

                        let distance = Math.Sqrt(p.x * p.x + p.y * p.y)

                        where distance < 500.0

                        select new { p.x, p.y, distance };

 

    }

 

    // A simple function that returns a list of values that match the given input

    private IEnumerable<T> FindValue<T>(IEnumerable<T> input, T value)

    {

        foreach (T item in input)

            if (item .Equals(value))

                yield return item;

    }

}

35. Never Overload Extension Methods

Recall from item 28 Augment Minimal Interface Contracts With Extension Methods and item 29 Enhance Constructed Types with Extension Methods that are three main reasons to create extension methods for interfaces or types:

  1.  Adding default implementation to interfaces

  2. Creating behaviors on closed generic types, and

  3. Creating composable interfaces.

However, extension methods are not always a good way to express your designs. In all those cases, you made some enhancements to an existing type definition, but those enhancements did not fundamentally change the behavior of the type. Suppose that you write an extension method on some class, say Person, to producea report of the person on the console. Later you find that you need to create a report in XML format as well (see namespaces ConsoleExtensionsBAD and XMLExtensionsBAD below.)

The problem in these two namespaces is this: Switching a using statement in the source file changes the format of the report! If a developer uses the wrong namespace, the program behavior changes. If a developer forgets to use any of the extension namespaces, the program won't compile. If a developer needs both of the namespaces in different methods, he/she must split the class definition into different files, based on which extension method is needed. Using both namespaces causes a compiler error on an ambiguous reference.

The use of extension methods in these cases is fundamentally wrong: Formatting a Person object for either XML or a console report is not part of the Person type, but instead more closely belongs to the outside environment that uses the Person object.

The key point is this: Extension methods should be used to enhance a type with functionality that naturally extends a type. You should create extension methods only to add functionality that would logically be part of that type. Class PersonReports below illustrates the proper solution to create reports.

// Bad start. Extending classes using extension methods

namespace ConsoleExtensionsBAD

{

    public static class ConsoleReport

    {

        public static string Format(this Person target)

        {

            return string.Format("{0,20}, {1,15}",

                target.LastName, target);

        }

    }

}

 

// Even worse. Ambiguous extension methods in different namespaces.

namespace XmlExtensionsBAD

{

    public static class XmlReport

    {

        public static string Format(this Person target)

        {

            return new XElement("Person",

                new XElement("LastName", target.LastName),

                new XElement("FirstName", target.FirstName)

                ).ToString();

        }

    }

}

 

// Proper way to create reports rather than using extension methods

public static class PersonReports

{

    public static string FormatAsText(Person target)

    {

        return string.Format("{0,20}, {1,15}", target.LastName, target.FirstName);

    }

    public static string FormatAsXML(Person target)

    {

        return new XElement("Person",

                                new XElement("LastName", target.LastName),

                                new XElement("FirstName", target.FirstName) ).ToString();

    }

}

LINQ

Expression Tree Basics

An expression tree provides a method of translating executable code into data. This can be very valuable if you want to modify or transform code before executing it. In particular, it can be useful if you want to transform C# code such as a LINQ query expression into code that operates on another process, such as a SQL database. Expression trees are not executable code, they are a form of data structure. So how does one translate the raw code found in an expression into an expression tree? See ShowBasicLambdaExpression() method.

Using Visual Studio Expression Tree Visualizer debug tool:

  1. Download ExpressionTreeVisualizer from http://code.msdn.microsoft.com/csharpsamples. Select Downloads tab and download CSharpSamples.zip (English).

  2. Save downloaded file in VS.NET 22008 samples folder. Select Help | Samples menu and click on 'Local Samples Folder'.

  3. Extract samples and build ExpressionTreeVisualizer.

  4. Copy ExpressionTreeVisualizer.dll into My Documents\Visual Studio 2008\Visualizers. See Tools | Options | Projects and Solutions | General for full path.

  5. Run a project that contains an Expression<T>. Set a breakpoint on the expression. Hover your mouse under the variable expression and a small Quick Info box with a magnifying glass will appear. Click on the magnifying class to view the expression tree visualizer.

class ExpressionTreeBasics

{

    /// <summary>

    /// Consider the following very simple lambda expression:

    ///

    ///     Func<int, int, int> function = (a,b) => a + b;

    ///

    /// This statement consists of three sections:

    ///     1. A declaration: Func<int, int, int> function

    ///     2. An equals operator: =

    ///     3. A lambda expression: (a,b) => a + b;

    ///

    /// The variable function points at raw executable code that knows how to add

    /// two numbers.

    ///

    /// In the code below, use ExpressionTreeVisualizer to view 'expressionAdd' variable.

    /// Note that there are four properties in the Expression<TDelegate> class:

    ///     1. Body: Retrieve the body of the expression.

    ///     2. Parameters: Retrieve the parameters of the lambda expression.

    ///     3. NodeType: Gets the ExpressionType for some node in the tree. This is an

    ///        enumeration of 45 different values, representing all the different possible

    ///        types of expression nodes, such as those that return constants, those that

    ///        return parameters, those that decide whether one value is less than another,

    ///        etc.

    ///     4. Type: Gets the static type of the expression. In this case, the expression

    ///         is of type Func<int, int, int>.

    ///

    /// Quick Notes on IQueryable<T> and IEnumerable<T>

    /// The query expressions found in LINQ to Objects return IEnumerable<T> rather than

    /// IQueryable<T>. Why does LINQ to Objects use IEnumerable<T> and LINQ to SQL use

    /// IQueryable<T>?

    ///

    /// Here is the declaration for IEnumerable<T>:

    ///     public interface IEnumerable<T> : IEnumerable

    ///     {

    ///         IEnumerator<T> GetEnumerator();

    ///     }

    ///    

    /// As you can see, IEnumerable<T> does not contain a field of type Expression. This points

    /// to a fundamental difference between LINQ to Objects and LINQ to SQL. The latter makes

    /// heavy use of expression trees, but LINQ to Objects uses them rarely.

    ///

    /// Why are expression trees not a standard part of LINQ to Objects? Consider this simple

    /// LINQ to Objects query expression:

    ///

    ///     List<int> list = new List<int>() {1,2,3,4,5};

    ///     var q = from n in list where n < 2 select n;

    ///  

    /// We can convert the query expression 'q' directly into .NET code that can be executed.

    /// It is not necessary to translate this query into a string that can be passed to another

    /// process in order to get the proper answer.

    ///

    /// </summary>

    public void ShowBasicLambdaExpression()

    {

        // A simple delegate that uses Lambda expression

        // Note that Func is a delegate that is declared in System namespace as follows:

        //  public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);

        Func<int, int, int> Add = (int a, int b) => a + b;

        int nResult = Add(10, 20);

 

        // The lambda expression used for Add (above) is converted into an expression

        // tree declared to be of type Expression<T>. The identifier expression is not

        // executable code; it is a data structure called an expression tree.

        // Examine expressionAdd with the Expression Tree Visualizer

        Expression<Func<int, int, int>> expressionAdd = (int a, int b) => a + b;

 

        // A programmatic way to display some of the information shown in the expression

        // tree visualizer

        Trace.WriteLine("Param 1: " + expressionAdd.Parameters[0] + ", Param 2: " + expressionAdd.Parameters[1]);

 

        // After converting code into data, we can convert data back into code. The following converts an expression

        // tree into executable code

        nResult = expressionAdd.Compile()(10, 20);

    }

 

    /// <summary>

    /// ShowBasicLambdaExpression gave an abstract conceptual understanding of an expression tree.

    /// The following examines the key role that an expression tree plays in LINQ, and particularly

    /// in LINQ to SQL.

    ///

    /// In the following query, q if of type IQueryable. Here is the declaration of IQueryable:

    ///     public interface IQueryable : IEnumerable

    ///     {

    ///         Type ElementType { get; }

    ///         Expression Expression { get; }

    ///         IQueryProvider Provider { get; }

    ///     }

    /// IQueryable.Expression is designed to hold the expression tree associated with an instance of

    /// IQueryable. Examine 'q' with the Expression Tree Visualizer and note the complexity of the

    /// data structure!

    ///

    /// The main question remains: Why Convert a LINQ to SQL Query Expression into an Expression Tree?

    /// A LINQ to SQL query is not executed inside your C# program. Instead, it is translated into SQL,

    /// sent across a wire, and executed on a database server. In other words, the query for 'q' is

    /// never actually executed inside your program. It is translated into SQL and then exectued on the

    /// database server. It is obviously going to be much easier to translate a data structure such as

    /// an expression tree into SQL than it is to translate raw IL or executable code into SQL.

    ///

    /// Therefore, expression trees were created in order to make the task of converting code such

    /// as a query expression into a string that can be passed to some other process and executed

    /// there. It is that simple.

    ///

    /// </summary>

    public void TestExpressionTreeInLINQToSQL()

    {

        // Create a data context

        MyDataContext ctxt = new MyDataContext();

 

        //the variable query that is returned by this LINQ expression is of type IQueryable

        //var q = from t in ctxt.tblFuturesTrades where t.Status == "Pending" select t;

 

    }

}

36. Understand How Query Expressions Map to Method Calls

LINQ is built on two concepts: a query language, and a translation from that query language into a set of methods. The C# compiler converts query expressions written in that query language into method calls. For example, a where clause translates to a call to a method named Where(), with the proper set of parameters. Therefore, every query expression has a mapping to a method call or calls.

The full query expression pattern contains eleven methods: Where, Select, SelectMany, Join, GroupJoin, OrderBy, OrderByDescending, GroupBy<K>, GroupBy<K,E>, ThenBy, and ThenByDescending.

The .NET Framework provides two general-purpose reference implementations of this pattern:

  1. System.Linq.Enumerable: The methods in this class provide an implementation of  the standard query operators for querying data sources that implement IEnumerable<T>. This means that any object that implements IEnumerable<T> will have available a set of extension methods whose implementation is found in System.Linq.Enumerable.
     

  2. System.Linq.Queryable: The methods in this class provide an implementation of the standard query operators for querying data sources that implement IQueryable<T>. This means that any object that implements IQueryable<T> will have available a set of extension methods whose implementation is found in System.Linq.Queryable. IQueryable<T> interface is intended for implementation by query providers.

Therefore, System.Linq.Enumerable provides extension methods for IEnumerable<T> and System.Linq.Queryable provides extension methods for IQuerable<T>. IEnumerable<T> is used for LINQ to Objects, whereas IQueryable<T> is designed for LINQ providers which need to translate expression trees into other forms - web service calls, SQL, LDAP etc.

class Item36

{

    /// <summary>

    /// Displays few basic LINQ select operations

    /// </summary>

    public void TestLINQBasics()

    {

        // Create a list of numbers

        int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

 

        // The following three statements are equivalent

        // The expression 'from n in numbers' binds the range variable n to each value

        // in numbers. The where clause define a filter whose output is a proper subset

        // of the input sequence containing only those elements that satisfy the predicate.

        // Finally, the select is used to transform one input element to a different

        // element or to a different type. In the 2nd statement below 'select' is

        // redundant and can be removed. Note that a proper select method must produce

        // exactly one output element for each input element. Also, a proper implementation

        // of Select must not modify the items in the input sequence.

        var first5numbers_v1 = from n in numbers where n < 5 select n;

        var first5numbers_v2 = numbers.Where((int n) => n < 5).Select((int m) => m);

        var first5numbers_v3 = numbers.Where((int n) => n < 5);

 

        // Select is used to transform or project one input element into a different element

        var squares1 = from n in numbers select n * n;

        foreach (var v in squares1) Trace.WriteLine(v);

 

        // Select is used to transform or project one input element into a different type

        var squares2 = from n in numbers select new {Number = n, Square = n^2};

        foreach (var v in squares2) Trace.WriteLine("Number: " + v.Number + ", Square: " + v.Square);

 

        // Same as squares2

        var squares3 = numbers.Select((int n) => new { Number = n, Square = n ^ 2 });           

    }

 

    /// <summary>

    /// Explores ordering by queries

    /// </summary>

    public void TestLinqOrdering()

    {

        // Create an array of employees (note syntax for using anonymous types)

        var Employees = new[] { new {Age=20, FirstName="Y", LastName="G"},

                                new {Age=30, FirstName="A", LastName="A" },

                                new {Age=30, FirstName="Z", LastName="W" },

                                new {Age=30, FirstName="B", LastName="A" },

                                new {Age=40, FirstName="N", LastName="M" },

                               };

 

        // Ordering relations map to the OrderBy and ThenBy methods. The following two

        // statements, p1 and p2,  are equivalent. Notice in the definition of the query

        // expression pattern that ThenBy operates on a sequence returned by OrderBy or

        // ThenBy. The output from both is:

        //  Age: 40, LastName: M, FirstName: N

        //  Age: 30, LastName: A, FirstName: A

        //  Age: 30, LastName: A, FirstName: B

        //  Age: 30, LastName: W, FirstName: Z

        {

            var p1 = from e in Employees

                     where e.Age >= 30

                     orderby e.Age descending, e.LastName, e.FirstName

                     select e;

 

            var p2 = Employees.Select(e => e).

                                Where(e => e.Age >= 30).

                                OrderByDescending(e => e.Age).ThenBy(e => e.LastName).ThenBy(e => e.FirstName);

 

            foreach (var p in p1) Trace.WriteLine("Age: " + p.Age + ", LastName: " + p.LastName + ", FirstName: " + p.FirstName);

            foreach (var p in p2) Trace.WriteLine("Age: " + p.Age + ", LastName: " + p.LastName + ", FirstName: " + p.FirstName);

        }

 

        // This transformation is not the same if the orderby clauses are expressed as

        // different clauses. The following query sorts the sequence entirely by LastName,

        // then sorts the entire sequence again by FirstName, and then sorts again by Age.

        // The output from both is:

        //  Age: 30, LastName: A, FirstName: A

        //  Age: 30, LastName: A, FirstName: B

        //  Age: 40, LastName: M, FirstName: N

        //  Age: 30, LastName: W, FirstName: Z

        {

            var p1 = from e in Employees

                     where e.Age >= 30

                     orderby e.Age

                     orderby e.LastName

                     orderby e.FirstName

                     select e;

 

            var p2 = Employees.Select(e => e).

                                Where(e => e.Age >= 30).

                                OrderBy(e => e.Age).OrderBy(e => e.LastName).OrderBy(e => e.FirstName);

 

            foreach (var p in p1) Trace.WriteLine("Age: " + p.Age + ", LastName: " + p.LastName + ", FirstName: " + p.FirstName);

            foreach (var p in p2) Trace.WriteLine("Age: " + p.Age + ", LastName: " + p.LastName + ", FirstName: " + p.FirstName);

        }

    }

 

    /// <summary>

    /// The following investigates expression translations that involve multiple steps.

    /// Those queries involve either groupings or multiple 'from' clauses that introduce

    /// continuations. Query expressions that contain continuations are translated into

    /// nested queries. Then those nested queries are translated into methods.

    /// </summary>

    public void TestNestedQueries()

    {

        // Create an array of employees. Note the use of anonymous types

        var Employees = new[] { new {Age=20, FirstName="Y", LastName="G"},

                                new {Age=30, FirstName="A", LastName="A" },

                                new {Age=30, FirstName="Z", LastName="W" },

                                new {Age=30, FirstName="B", LastName="A" },

                                new {Age=40, FirstName="N", LastName="M" }};

 

        // The following queries are all identical. r1 is the original query.

        // Before any other translations are performed, the continuation is

        // translated into a nested query (r2). Once the nested query is created,

        // the methods translate into r3 query

        // Each of the following queries gives the following output

        //  Age: 20, Size: 1

        //  Age: 30, Size: 3

        //  Age: 40, Size: 1

        {

            var r1 = from e in Employees

                     group e by e.Age into agegroups

                     select new { Age = agegroups.Key, Size = agegroups.Count() };

 

            var r2 = from agegroups in

                         from e in Employees group e by e.Age

                     select new { Age = agegroups.Key, Size = agegroups.Count() };

 

            var r3 = Employees.GroupBy(e => e.Age).Select(agegroups => new { Age = agegroups.Key, Size = agegroups.Count() });

 

            foreach (var r in r1) Trace.WriteLine("Age: " + r.Age + ", Size: " + r.Size);

            foreach (var r in r2) Trace.WriteLine("Age: " + r.Age + ", Size: " + r.Size);

            foreach (var r in r3) Trace.WriteLine("Age: " + r.Age + ", Size: " + r.Size);

        }

 

        // The foregoing query shows a GroupBy that returns a single sequence. The other

        // GroupBy method in the query expression pattern returns a sequence of groups

        // in which each group contains a key and a list of values.

        // GroupBy methods produce a sequence of key/value list pairs; the keys are the

        // group selectors, and the values are the sequence of items in the group

        // Output from both is:

        //  Age: 20

        //  Employee Age: 20, FirtName: Y, LastName: G

        //  Age: 30

        //  Employee Age: 30, FirtName: A, LastName: A

        //  Employee Age: 30, FirtName: Z, LastName: W

        //  Employee Age: 30, FirtName: B, LastName: A

        //  Age: 40

        //  Employee Age: 40, FirtName: N, LastName: M

        {

            var r1 = from e in Employees

                     group e by e.Age into agegroups

                     select new { Age = agegroups.Key, Employees = agegroups.AsEnumerable() };

 

            var r2 = Employees.GroupBy(e => e.Age).Select(agegroups => new { Age = agegroups.Key, Employees = agegroups.AsEnumerable() });

            foreach (var r in r1)

            {

                Trace.WriteLine("Age: " + r.Age);

                foreach (var e in r.Employees)

                    Trace.WriteLine("Employee Age: " + e.Age + ", FirtName: " + e.FirstName + ", LastName: " + e.LastName);

            }

 

            foreach (var r in r2)

            {

                Trace.WriteLine("Age: " + r.Age);

                foreach (var e in r.Employees)

                    Trace.WriteLine("Employee Age: " + e.Age + ", FirtName: " + e.FirstName + ", LastName: " + e.LastName);

            }

        }

    }

 

    /// <summary>

    /// SelectMany performs a cross join on the two source sequences

    /// </summary>

    ///

    public class ParentDetails

    {

        public string ParentName { get; set; }

        public List<string> Children { get; set; }

    }

    public void TestSelectMany()

    {

        // Create a collection of parent and their respective children

        ParentDetails[] details = { new ParentDetails { ParentName="Mr. A", Children = new List<string>(){"X", "Y"}},

                               new ParentDetails { ParentName="Mr. B", Children = new List<string>(){"G", "J"}},

                               new ParentDetails { ParentName="Mr. C", Children = new List<string>(){"J", "R", "K"}} };

 

        // Query using SelectMany

        var q1_SelectMany = details.SelectMany((pd) => pd.Children);

 

        // Only one foreach statement is required since the result is one-dimensional

        // Output is:

        // X

        // Y

        // G

        // J

        // J

        // R

        // K

        foreach (string child in q1_SelectMany)

            Trace.WriteLine(child);

 

        // Query using Select

        var q1_Select = details.Select((pd) => pd.Children);

 

        // Two foreach statements are required because q2 returns a collection of arrays#

        // Output is:

        // X

        // Y

        // G

        // J

        // J

        // R

        // K

        foreach (List<string> children in q1_Select)

            foreach (string child in children)

                Trace.WriteLine(child); 

    }

}

37. Prefer Lazy Evaluation Queries

When you define a query, you do not actually get the data and populate a sequence. You are actually defining only the steps that will be executed when you choose to  iterate that query. This means that each new enumeration produces new results. This is called lazy evaluation. Lazy evaluation is not always what you want. The other option is eager evaluation where you retrieve the results once and retrieve them now.

Every time you write a query be enumerated more than once, you need to consider which behavior you want. Do you want a snapshot of your data (eager evaluation), or do you want to create a description of the code you will execute in order to create the sequence of values (lazy evaluation)?

Some query expressions must retrieve the entire sequence before they can proceed to create their answer. This means that Query expressions may operate on infinite sequences! See TestInfiniteSequences for an example.

There are a number of query operators that must have the entire sequence in order to operate correctly. where uses the entire sequence. orderby needs the entire sequence to be present.  max and min need the entire sequence. There's no way to perform these operations without examining every element in the sequence. When you need these capabilities, you'll use these methods.

You also need to think about the consequences of using methods that require access to the entire sequence. As you've seen, you need to avoid any methods that require the entire sequence if the sequence might be infinite. Second, even if the sequence is not infinite, any query methods that filter the sequence should be front-loaded in the query. If the first steps in your query remove some of the elements from the collection, that will have a positive effect on the performance of the rest of the query. For example, queries that filter before ordering may have better performance than queries that order and then filter

The discussion so far has been on using lazy evaluation. In most cases, that's the best approach. At other times, though, you do want a snapshot of the values taken at a point in time. There are two methods you can use to generate the sequence immediately and store the results in a container: ToList() and ToArray(). Both methods perform the query and store the results in a List<T> or an Array, respectively. By forcing the query to execute immediately, these methods capture a snapshot of the data right now.

class Item37

{

    /// <summary>

    /// In this example of lazy evaluation, the sequence variable 'dates' does not hold

    /// the elements created. Rather, it holds the expression tree that can create the

    /// sequence. Notice that the sequence is generated each time it is iterated, as

    /// evidenced by the different time stamps.

    ///

    /// </summary>

    public void TestLazyEvaluation()

    {

        // Define the query to get time (does not execute the query!)

        IEnumerable<DateTime> dates = Generate<DateTime>(5, () => (DateTime.Now));

 

        // The following iteration executes the query! Note the output

        //  12:20:25.333509

        //  12:20:25.358898

        //  12:20:25.358898

        //  12:20:25.359875

        //  12:20:25.360851

        foreach (DateTime date in dates)

            Trace.WriteLine(date.ToString("hh:mm:ss.FFFFFF"));

 

        // The following iteration executes the query! Note that the output is differnet

        // from the first iteration above

        //  12:20:25.360851

        //  12:20:25.361828

        //  12:20:25.361828

        //  12:20:25.362804

        //  12:20:25.363781

        foreach (DateTime date in dates)

            Trace.WriteLine(date.ToString("hh:mm:ss.FFFFFF"));

    }

 

    /// <summary>

    /// You can use lazy evaluation to compose queries from existing queries. Instead of

    /// retrieving the results from one query and then processing them as a separate step,

    /// you can compose queries in different steps and then execute the composed query only

    /// once.

    ///

    /// In the example below, q1 and q2 share functional composition, not data. q2 is not

    /// built by enumerating the values in q1 and modifying each value. Rather, it is created

    /// by executing the code that produces q1, followed by the code that produces q2. If you

    /// iterate the two queries at different times, you'll see unrelated sequences. q2 will

    /// not contain the converted values from q1. Instead, it will contain totally new values.

    /// </summary>

    public void TestFunctionalCompositionInLazyEvaluation()

    {

        int nStartValue = 0;

        var q1 = Generate(5, () => nStartValue++);

        var q2 = from value in q1 select value * 10;

 

        // The following iteration executes the functional composition of q1 and q2

        // The following values are produced

        //  0

        //  10

        //  20

        //  30

        //  40

        foreach (int nValue in q2)

            Trace.WriteLine(nValue);

    }

 

    /// <summary>

    /// The 'numbers' sequences only generates 5 numbers even though Generate() can generate

    /// up to int.MaxValue numbers.

    ///

    /// However, the 'numbers2' sequence will run forever. It runs forever because the query

    /// must examine every single number to determine which methods match. This version of

    /// the same logic requires the entire sequence!

    /// </summary>

    public void TestInfiniteSequences()

    {

        // Generate only 5 numbers

        int nStartNumber = 0;

        IEnumerable<int> numbers = Generate(int.MaxValue, () => (nStartNumber++)).Take(5);

 

        // Iterate results

        foreach (int nValue in numbers)

            Trace.WriteLine(nValue);

 

        nStartNumber = 0;

        IEnumerable<int> numbers2 = Generate(int.MaxValue, () => (nStartNumber++)).Where( (nValue) => (nValue < 5));

 

        // -------------> RUNS FOREVER <-----------

        foreach (int nValue in numbers2)

            Trace.WriteLine(nValue);

    }

  

    /// <summary>

    ///  Generates a sequence of values. nCount determines the number of values to

    ///  generate and generator is a delegate that generates actual values

    /// </summary>

    private IEnumerable<TResult> Generate<TResult>(int nCount, Func<TResult> generator)

    {

        for (int i = 0; i < nCount; i++)

            yield return generator();

    }

}

39. Avoid Throwing Exceptions in Functions and Actions

When you create code that executes over a sequence of values and the code throws an exception somewhere in that sequence processing, you'll have problems recovering state. You don't know how many elements were processed, if any. You don't know what needs to be rolled back. You can't restore the program state at all. See TestExceptionInAction() method below.

Note that not every method exhibits this problem. Many methods examine a sequence but do not modify it. We would not have this problem if we used another action, say DisplaySalary, that would print the salary without modifying it. You fix the situation illustrated by UpdateSalary method below by guaranteeing that whenever the method does not complete, the observable program state does not change. You can implement this in various ways:

  1. Rework the action so that you can ensure that the action method, expressed earlier in the Action<T> method, never throws an exception. In many cases, it is possible to test any failure conditions before modifying each element in the sequence. See UpdateSalaryFix1 method below for an example.
  2. If approach 1 is not possible, i.e. you could not avoid the possibility of an exception, rework the algorithm by doing all the work on a copy and then replacing the original sequence with the copy only if the operation completes successfully. See method TestExceptionInAction2() below. You can see the cost of those changes here. First, there's quite a bit more code than in the earlier versions. We've also changed the performance metrics for the application. This newer version creates a second copy of all the employee records and then swaps the reference to the new list of employees with the reference to the old list. If the  employee list is large, that could cause a big performance bottleneck.

Also note that this new version limits your ability to compose operations using multiple functions. This code snippet caches the full list. This means that its modifications aren't composed along with other transformations in a single enumeration of the list. Each transformation becomes an imperative operation. In practice, you can work around this issue by creating one query statement that performs all the transformations. You cache the list and swap the entire sequence as one final step for all the transformations. Using that technique, you preserve the composability and still provide the strong exception guarantee.

class Item39

{

    public void TestExceptionInAction()

    {

        // Create a list of Persons           

        List<MyEmployee> lstEmp = new List<MyEmployee>(){ new MyEmployee("X", 2000.0),

                                                          new MyEmployee("Y", 2000.0),

                                                          new MyEmployee("Z", 2000.0)};

 

        try

        {

            // Update salary for all employees

            Action<MyEmployee> action = UpdateSalary;

            lstEmp.ForEach(action);

        }

        catch (Exception ex)

        {

            // Enumerate over all employees to show current state. Note some employees

            // have their salary incremented, but not others. Output:

            //  X/4000

            //  Y/2000

            //  Z/2000

            foreach (MyEmployee emp in lstEmp)

                Trace.WriteLine(emp.Name + "/" + emp.Salary);

        }

    }

 

    public void TestExceptionInAction2()

    {

        // Create a list of Persons           

        List<MyEmployee> lstEmp = new List<MyEmployee>(){ new MyEmployee("X", 2000.0),

                                                          new MyEmployee("Y", 2000.0),

                                                          new MyEmployee("Z", 2000.0)};

 

        try

        {

            // Create a copy of the original list

            List<MyEmployee> lstEmpCopy= new List<MyEmployee>();

            foreach (MyEmployee emp in lstEmp)

                lstEmpCopy.Add(new MyEmployee(emp.Name, emp.Salary));

 

            // Update salary for all employees ON A COPY of the original list

            Action<MyEmployee> action = UpdateSalary;

            lstEmpCopy.ForEach(action);

 

            // No exception. Now we can copy the altered list into the original list

            lstEmp.Clear();

            lstEmp.AddRange(lstEmpCopy);

        }

        catch (Exception ex)

        {

            // Failed to updated list of employees. State of the original list is maintained

        }

 

        // Show the state of the original list

        foreach (MyEmployee emp in lstEmp)

            Trace.WriteLine(emp.Name + "/" + emp.Salary);

    }

  

    /// <summary>

    /// Helper Action<T> method to update salaries. Throws an exception to illustrate effect of

    /// throwing exceptions in an Action<T> function

    /// </summary>

    private void UpdateSalary(MyEmployee emp)

    {

        // Update salary for the given employee

        emp.Salary = emp.Salary * 2.0;

 

        // Simulate an exception

        throw new ApplicationException("Employee " + emp.Name + " is no longer on the pay roll");

    }

 

    private void UpdateSalaryFix1(MyEmployee emp)

    {

        // Update salary for the given employee, only if the employee is on the pay roll

        if (IsEmployeeOnPayRoll(emp))

            emp.Salary = emp.Salary * 2.0;

    }

 

    private bool IsEmployeeOnPayRoll(MyEmployee emp) { return true; }

 }

 

namespace Item39NS

{

    public class MyEmployee

    {

        public string Name { get; set; }

        public double Salary { get; set; }

 

        public MyEmployee(string name, double salary)

        {

            Name = name;

            Salary = salary;

        }

    }

}

40. Distinguish Early from Deferred Execution

Will the following two lines of code behave the same way?

object o = Foo( Method1(), Method2(), Method3() );    
object o = Foo( () => Method(), () => Method2(), () => Method3() );

At runtime, first line of code calls Method1() to generate first parameter to Foo, then calls Method2() to generate second parameter, then calls Method3() to generate third and last parameter. It then calls Foo with the three generated parameters. This is Imperative code'; it details step-by-step instructions that explain how something gets done.

As for the second line, it does the following at runtime:

  1. It calls Foo(), passing the lambda expressions that could call Method1, Method2, and Method3.

  2. Inside Foo, if and only if the result of Method1 is needed, Method1 is called.

  3. Inside Foo, if and only if the result of Method2 is needed, Method2 is called.

  4. Inside Foo, if and only if the result of Method3 is needed, Method3 is called.

  5. Method1, Method2, and Method3 may be called in any order, as many times (including zero) as needed.

The second line of code illustrates Declarative code; the declarative model may or may not execute all or any of the methods. The declarative version may execute any of the methods more than once. This is the difference between (1) calling a method and passing the results to a method and (2) passing a delegate to the method and letting the method call the delegate. You may get different results from different runs of the application, depending on what actions take place in these methods.

If data and methods are interchangeable, which should you choose? And, more importantly, when should you choose which? The most important difference is that data must be preevaluated, whereas a method can be lazy-evaluated. When you must evaluate data early, you must preevaluate the method and use the result as the data, rather than take a functional approach and substitute the method.

41. Avoid Capturing Expensive Resources

Recall that a closure is a function that can refer to and alter the values of variables defined in its declaring scope. In C# closures correspond to anonymous delegates:

Person person = new Person("Yazan");
Action<int> Add = new Action<T>(delegate (int y)
{
    person.PrintDetails();
}

Here the variable person can be accessed and modified inside the anonymous delegate. The main point is this: When you capture a variable in a closure (person in example above), the object referenced by that variable does not go out of scope until the last delegate referencing that captured variable goes out of scope. The implication is that you really don't know when local variables go out of scope if you return something that is represented by a delegate using a captured variable. To further explain this point, consider this construct:

int counter = 0;
IEnumerable<int> numbers = Extensions.Generate(30, () => counter++);

It generates code that looks something like this:

private class Closure
{
    public int generatedCounter;
    public int generatorFunc()
    {
        return generatedCounter ++;
    }
}

// usage
Closure c = new Closure();
c.generatedCounter = 0;
IEnumerable<int> sequence = Extensions.Generate(30, new Func<int>(c.generatorFunc));

The hidden nested class members have been bound to delegates used by Extensions.Generate. That can affect the lifetime of the hidden object and therefore can affect when any of the members are eligible for garbage collection. In other words, the local variable c lives beyond the end of the method. Problems arise when some variables hold on to expensive resources. They represent types that implement IDisposable and need to be explicitly cleaned up. These points are illustrated in CaptruingExpensiveResouces() method.

class Item41

{

    private const string FILEPATH = @"D:\Projects\MoreEffectiveCS\MoreEffectiveCS\C#3\Item31Input.txt";

 

    public void CaptruingExpensiveResouces()

    {

        /* Incorrect way of using ReadCSVFile. Does not close the file */

        {

            TextReader t = new StreamReader(FILEPATH);

            IEnumerable<string[]> lines = ReadCSVFile( t );

            DisplayLines( lines );

        }

 

        /* Incorrect way of using ReadCSVFile. Closes file before reading it */

        try

        {

            IEnumerable<string[]> lines = null;

            using (TextReader t = new StreamReader(FILEPATH))

            {

                lines = ReadCSVFile( t );                   

            }   // Files closed here. Stream has not beed read yet due to 'deferred execution'

 

            // File read during iteration. However file is close, hence exception

            // "Cannot read from a closed TextReader"

            DisplayLines( lines ); 

        }

        catch (Exception ex)

        {

            Trace.WriteLine( ex.Message );

        }

 

        /* Correct way of using ReadCSVFile */

        try

        {               

            using (TextReader t = new StreamReader(FILEPATH))

            {

                IEnumerable<string[]> lines = ReadCSVFile(t);

 

                // File read during iteration

                DisplayLines(lines);

            }   // Files closed here AFTER it has been read

        }

        catch (Exception ex)

        {

            Trace.WriteLine(ex.Message);

        }

 

        /* Last block of code works, but not all problems are that simple. This will lead

         to lots of duplicated code.*/

        try

        {

            IEnumerable<string> lines = ReadLines2(FILEPATH); ;

            IEnumerable<string[]> parsedLines = ReadCSVFile2(lines);

            DisplayLines(parsedLines);

        }

        catch (Exception ex)

        {

            Trace.WriteLine(ex.Message);

        }

    }

 

    /// <summary>

    /// Helper method return lines from a CSV file

    /// </summary>

    private IEnumerable<string[]> ReadCSVFile(TextReader reader)

    {

        var lines = from line in reader.ReadLines() select line.Split( new char[] {','} );

        return lines;

    }

 

    /// <summary>

    /// Displays data for debugging purposes

    /// </summary>

    /// <param name="lines"></param>

    private void DisplayLines( IEnumerable<string[]> lines )

    {

        foreach (var line in lines)

            Trace.WriteLine( string.Join( ",", line) );

    }

 

 

    private IEnumerable<string[]> ReadCSVFile2(IEnumerable<string> lines)

    {

        var parsedLines = from line in lines select line.Split(new char[] { ',' });           

        return parsedLines;

 

    }

 

    public static IEnumerable<string> ReadLines2(string path)

    {

        using (StreamReader reader = new StreamReader(path))

        {

            string line = reader.ReadLine();

            while (line != null)

            {

                yield return line;

                line = reader.ReadLine();

            }

        }

    }

}

 

namespace Item41NS

{

    /// <summary>

    /// Extends TextReader

    /// </summary>

    internal static class TextReaderExtensions

    {

        public static IEnumerable<string> ReadLines(this TextReader reader)

        {

            string line = reader.ReadLine();

            while (line != null)

            {

                yield return line;

                line = reader.ReadLine();

            }

        }

    }

}

42. Distinguish Between IEnumerable and IQueryable Data Sources

IQueryable<T> provides functionality to evaluate queries against a specific data source (typically SQL Server database) wherein the type of the data is not specified. The IQueryable interface inherits the IEnumerable interface so that if it represents a query, the results of that query can be enumerated. Enumeration causes the expression tree associated with an IQueryable object to be executed. The definition of executing an expression tree is specific to a query provider. For example, for a SQL Server database, executing an expression tree involves translating the expression tree to SQL and then executing this SQL against the database.

IEnumerable<T> on the other hand, exposes an enumerator, which supports a simple iteration over a collection of a specified type.

IQueryable<T> and IEnumerable<T> have very similar API signatures. IQueryable<T> derives from IEnumerable<T>. However, Their behaviours are different and their performance metrics can be very different.

class Item42

{

    /// <summary>

    /// The following two queries q1 and q2 return the same result, but they do their work

    /// in very different ways: The first query uses the normal LINQ to SQL version that is

    /// built on IQueryable functionality. The second version forces the database objects

    /// into IEnumerable sequences and does MORE OF ITS WORK LOCALLY.

    ///

    /// When the results of the first query are executed (answer1), the LINQ to SQL libraries

    /// compose the results from ALL the query statements. In the example below, this means that

    /// one call is made to the database. It also means that one SQL query performs both the

    /// where clause AND the orderby clause.

    ///

    /// In the second case, returning the first query as an IEnumerable<T> sequence means that

    /// subsequent operations use the LINQ to Objects implementation and are executed using

    /// delegates. The first statement causes a call to the database to retrieve all male employees.

    /// The second orders the set returned by the first call by employee Id. That sort operation

    /// occurs locally.

    ///

    /// The processing is different at every step of the way. Enumerable<T> extension methods

    /// use delegates for the lambda expressions as well as the function parameters whenever they

    /// appear in query expressions. Queryable<T>, on the other hand, uses expression trees to

    /// process those same function elements. An expression tree is a data structure that holds

    /// all the logic that makes up the actions in the query. The Enumerable<T> version must execute

    /// locally. The lambda expressions have been compiled into methods, and they must execute now

         /// on the local machine. This means that you need to pull all the data into the local application

        /// space from wherever it resides. You'll transfer much more data, and you'll throw away whatever

        /// isn't necessary. In contrast, the Queryable version parses the expression tree. After examining

        /// the expression tree, this version translates that logic into a format appropriate for the

        /// provider and then executes that logic where it is closest to the data location. The result

    /// is much less data transfer and better overall system performance.

    /// </summary>

    public void TestIQueryableAndIEnumerable()

    {

        // Create a context to the AdvanetureWorks database

        AdventureWorksLINQDataContext ctxt = new AdventureWorksLINQDataContext();

 

        // IQueryable query. Generates the following SQL (note the inclusion of order by clause)

        //  exec sp_executesql N'SELECT [t0].[EmployeeID], [t0].[BirthDate]

        //  FROM [HumanResources].[Employee] AS [t0]

        //  WHERE UNICODE([t0].[Gender]) = @p0

        //  ORDER BY [t0].[EmployeeID]',N'@p0 int',@p0=77

        // Also note the use of q1 and answer1, implicitly typed local variables (See Item 30)

        var q1 = from e in ctxt.Employees where e.Gender == 'M' select new { e.EmployeeID, e.BirthDate };

        var answer1 = from e in q1 orderby e.EmployeeID select e;

        foreach (var e in answer1)

            Trace.WriteLine(e.EmployeeID + "/" + e.BirthDate);

 

        // IEnumerable query. Generates the following SQL (note the absence of an order by clause)

        //  exec sp_executesql N'SELECT [t0].[EmployeeID], [t0].[BirthDate]

        //  FROM [HumanResources].[Employee] AS [t0]

        //  WHERE UNICODE([t0].[Gender]) = @p0',N'@p0 int',@p0=77

        var q2 = (from e in ctxt.Employees where e.Gender == 'M' select new { e.EmployeeID, e.BirthDate }).AsEnumerable();

        var answer2 = from e in q2 orderby e.EmployeeID select e;

        foreach (var e in answer2)

            Trace.WriteLine(e.EmployeeID + "/" + e.BirthDate);

    }

 

 

    /// <summary>

    /// IQueryable providers don't parse any arbitrary method. Instead, they understand a set of operators,

    /// and possibly a defined set of methods, that are implemented in the .NET Framework. If your queries

    /// contain other method calls (see q2 below), you may need to force the query to use the Enumerable

    /// implementation.

    ///

    /// For the querys below (q1 and q2) the first query works, because LINQ to Objects uses delegates to

    /// implement queries as method calls. The AsEnumerable() call forces the query into the local client

    /// space, and the where clause executes using LINQ to Objects. The second query throws an exception.

    /// The reason is that LINQ to SQL uses an IQueryable<T> implementation. LINQ to SQL contains an

    /// IQueryProvider that translates your queries into T-SQL. That T-SQL then gets remoted to the database

    /// engine, which executes the SQL statements in that context. q2 query attempts to include IsSales

    /// in the generated T-SQL, but IsSales is unknown to T-SQL, and therefore throws an exception.

    ///

    /// In a typical tradeoff of performance versus robustness, you can avoid the exception by translating

    /// the query result explicitly to an IEnumerable<T>. The downside of that solution is that the LINQ

    /// to SQL engine now returns the entire set of dbContext.Products from the database. Furthermore, the

    /// remainder of the query is executed locally. Because IQueryable<T> inherits from IEnumerable<T>,

    /// this method can be called using either source.

    /// </summary>

    public void TestArbitraryMethodsInIQueryable()

    {

        try

        {

            // Create a context to the AdvanetureWorks database

            AdventureWorksLINQDataContext ctxt = new AdventureWorksLINQDataContext();

 

            // Works as expected

            var q1 = from e in ctxt.Employees.AsEnumerable() where IsSales(e) select new { e.EmployeeID, e.Title };

            foreach (var e in q1)

                Trace.WriteLine("Employee ID: " + e.EmployeeID);

 

            // Throws the following System.NotSupportedException:

            // "Method 'IsSales(MoreEffectiveCS.Employee)' has no supported translation to SQL."

            var q2 = from e in ctxt.Employees where IsSales(e) select new { e.EmployeeID, e.Title };

            foreach (var e in q2)

                Trace.WriteLine("Employee ID: " + e.EmployeeID);

 

        }

        catch (Exception ex)

        {

            Trace.WriteLine(ex.Message);

        }

    }

    private bool IsSales(Employee e)

    {

        return e.Title.Contains("Sales");

    }

 

    /// <summary>

    /// AsQueryable() looks at the runtime type of the sequence. If the sequence is an IQueryable,

    /// it returns the sequence as an IQueryable. In contrast, if the runtime type of the sequence

    /// is an IEnumerable, AsQueryable() creates a wrapper that implements IQueryable using the

    /// LINQ to Objects implementation, and it returns that wrapper. You get the Enumerable

    /// implementation, but it's wrapped in an IQueryable reference.

    ///

    /// Using AsQueryable() gives you the maximum benefit. Sequences that already implement IQueryable

    /// will use that implementation, and sequences that support only IEnumerable will still work. When

    /// client code hands you an IQueryable sequence, your code will properly use the Queryable<T> methods

    /// and will support expression trees and foreign execution. And if you are working with a sequence

    /// that supports only IEnumerable<T>, then the runtime implementation will use the IEnumerable

    /// implementation

    /// </summary>

    public void TestAsQueryable()

    {

        // Create a context to the AdvanetureWorks database

        AdventureWorksLINQDataContext ctxt = new AdventureWorksLINQDataContext();

 

        // The following query maps to:

        //      exec sp_executesql N'SELECT [t0].[EmployeeID], [t0].[Title]

        //      FROM [HumanResources].[Employee] AS [t0]

        //      WHERE [t0].[Title] LIKE @p0',N'@p0 nvarchar(7)',@p0=N'%Sales%'

        var q = from e in ctxt.Employees.AsQueryable()

                where e.Title.Contains("Sales") select new { e.EmployeeID, e.Title };

        foreach (var e in q)

            Trace.WriteLine("Employee ID: " + e.EmployeeID);

    }

}

43. Use Single() and First() to Enforce Semantic Expectation on Queries

When you write a query that is supposed to return exactly one element, you should use Single(). Single() returns exactly one element. If no elements exist, or if multiple elements exist, then Single() throws an exception. The exception helps you make a quick diagnosis and correct the problem. Note that Single() immediately evaluates the query and either returns the single element, or throws an exception.

If your query can return zero or one element, you can use SingleOrDefault(). However, remember that SingleOrDefault() still throws an exception when more than one value is returned. You are still expecting no more than one value returned from your query expression.

There are times when you expect to get more than one value but you want a specific one. The best choice is First() or FirstOrDefault(). Both methods return the first element in the returned sequence. If the sequence is empty, the default is returned.

class Item43

{

    public void TestSingle()

    {

        // Create a list of Person objects

        var persons = new List<Person>{ new Person{FirstName="A", LastName="X", Salary=1000},

                                          new Person{FirstName="A", LastName="Y", Salary=2000},

                                          new Person{FirstName="A", LastName="Z", Salary=3000} };

 

        try

        {

            // Throws an exception. More than one object whose FiratName is "A"

            var person = (from p in persons where p.FirstName == "A" select p).Single();

        }

        catch (Exception ex)

        {

            Trace.WriteLine(ex.Message);    // ERROR: "Sequence contains more than one element"

        }

 

        try

        {

            // Throws an exception. There is no object whose FiratName is "A". Should have

            // used SingleOrDefault(). See TestSingleOrDefault()

            var person = (from p in persons where p.FirstName == "B" select p).Single();

        }

        catch (Exception ex)

        {

            Trace.WriteLine(ex.Message);    // ERROR: "Sequence contains no elements"

        }

    }

 

    public void TestSingleOrDefault()

    {

        // Create a list of Person objects

        var persons = new List<Person>{ new Person{FirstName="A", LastName="X", Salary=1000},

                                          new Person{FirstName="A", LastName="Y", Salary=2000},

                                          new Person{FirstName="A", LastName="Z", Salary=3000} };

 

        try

        {

            // Throws an exception. More than one object whose FiratName is "A"

            var person = (from p in persons where p.FirstName == "A" select p).SingleOrDefault();

        }

        catch (Exception ex)

        {

            Trace.WriteLine(ex.Message);    // ERROR: "Sequence contains more than one element"

        }

 

        try

        {

            // Does NOT throw an exception. The query returns NULL

            var person = (from p in persons where p.FirstName == "B" select p).SingleOrDefault();

        }

        catch (Exception ex)

        {

            Trace.WriteLine(ex.Message);   

        }

    }

 

    public void TestFirstOrDefault()

    {

        // Create a list of Person object

        var persons = new List<Person>{ new Person{FirstName="A", LastName="X", Salary=1000},

                                          new Person{FirstName="A", LastName="Y", Salary=2000},

                                          new Person{FirstName="A", LastName="Z", Salary=3000} };

 

        try

        {

            // Get the person with the highest salary

            var HighestPaid = (from p in persons orderby p.Salary descending select p).First();

 

            // Get the person with the second highest salary. Note that we use First() rather than Take()

            // to emphasize that we wanted exactly one element, and not a sequence containing one element

            var SecondHighestPaid = (from p in persons orderby p.Salary descending select p).Skip(1).First();

 

            // Returns null

            var Paid25000 = (from p in persons where p.Salary == 2500 select p).FirstOrDefault();

 

            // Throws an exception: "Sequence contains no elements"

            var Paid35000 = (from p in persons where p.Salary == 3500 select p).First();

 

        }

        catch (Exception ex)

        {

            Trace.WriteLine(ex.Message);

        }

    }

}

 

namespace Item43NS

{

    internal class Person

    {

        public string FirstName { get; set; }

        public string LastName { get; set; }

        public double Salary { get; set; }

    }

}

Miscellaneous

45. Minimize the Visibility of Nullable Types

Nullable types require more checks than non-nullable types. It makes more sense to use non-nullable structs whenever you can and to limit nullable types to those algorithms that require the nullable abstraction. Programming against nullable types is more complicated than programming against the corresponding non-nullable value. Nullables mean extra checking: What should happen when the value is missing? The answer will vary, but for every algorithm, the missing value should be interpreted in some known way. Your goal should be to isolate the extra work required for nullable values to the smallest set of code.

TestNullableSemantics() method below illustrates effect applying comparison and numeric operations to nullable types.

TestNullableSerialization() illustrates some of the issues encountered when serializing types that contain nullables. Those member elements appear to be typed as value types, and yet the value itself is null. Tools that build classes from XML documents create ints, rather than nullable ints. Deserialization using those tools would produce the same errors when your program encounters null values.

Nullable types also introduce complicated behavior when you work with virtual methods defined in System.Object or with interfaces implemented by the underlying value type. Those operations will cause a boxing conversion of the enclosed value type to System.Object or to the interface pointer. See TestNullableBoxing() and TestNullableBoxing2() methods.

class Item45

{

    /// <summary>

    /// Nullable types add semantics to everyday operations on value types:

    ///     * Any comparison involving a NULL returns FALSE.

    ///     * Nullables support equality

    ///     * Any numeric operation involving a nullable numeric type with no value results in a

    ///       nullable type with no value

    ///     * The fact that any null in a numeric expression causes the result of that expression

    ///       to be null, means that you often must define default values for those operations.

    ///       This is easily accomplished using the coalescing operator (??).

    ///    

    /// </summary>

    public void TestNullableSemantics()

    {

        int?    n1 = 0;

        int?    n2 = default(int?);            // n2 is null

        int?    n3 = default(int?);            // n3 is null

 

        // Comparisons

        Trace.WriteLine("n1 < n2: " + (n1 < n2));       // n1 < n2: False

        Trace.WriteLine("n1 > n2: " + (n1 > n2));       // n1 > n2: False

        Trace.WriteLine("n1 == n2: " + (n1 == n2));     // n1 == n2: False

        Trace.WriteLine("n2 == n3: " + (n2 == n3));     // n2 == n3: True

 

        // Numeric Operations

        Trace.WriteLine("n1 + n2 = " + (n1 + n2).HasValue);     // n1 + n2 = False

        Trace.WriteLine("n1 * n2 = " + (n1 * n2).HasValue);     // n1 * n2 = False

        Trace.WriteLine("n1 / n2 = " + (n1 / n2).HasValue);     // n1 / n2 = False

        Trace.WriteLine("n2 + n3 = " + (n2 + n3).HasValue);     // n2 + n3 = False

 

        // A null in a numeric expression returns null. The coalescing operator is

        // used to return a default value. The following shows different usages of the

        // (??) operator.

        int? nResult1 = (n1 + n2) ?? 0;             // nResult1 = 0

        int? nResult2 = (n1 ?? 0) + (n2 ?? 0);      // nResult2 = 0

        int? nResult3 = (n1 ?? 0) / (n2 ?? 1);      // nResult3 = 0

    }

 

    /// <summary>

    /// In the following code we serialize a nullable int and then deserialize it back.

    /// Notice that the type of the generated XML element is int and not int?. The XML

    /// element does not contain any indication that the integer may be missing. Yet,

    /// as you can see from the node, it is missing.

    ///

    /// When deserialing the value back, you get a NullReferenceException. This makes

    /// sense when you think about it. You saved a nullable int, which could contain

    /// every integer value as well as the null value. When you read that value back in,

    /// you implicitly converted the int? to an int. The null value is not valid for a

    /// value type, so your code generated an exception.

    /// </summary>

    public void TestNullableSerialization()

    {

        int? n = default(int?);

 

        // Serialize a nullable filed

        XmlSerializer serializer = new XmlSerializer(typeof(int?));

        StringWriter writer = new StringWriter();

        serializer.Serialize(writer, n);

 

        // Show result of serializing a nullable int. The following is produced

        //  <?xml version="1.0" encoding="utf-16"?>

        //  <int xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:nil="true" />

        Trace.WriteLine(writer.ToString());

 

        // Now deserialize the XML stream

        StringReader reader = new StringReader(writer.ToString());

        int n2 = (int)serializer.Deserialize(reader);           // Throws NullReferenceException exception

        Trace.WriteLine("Deserialized int? : " + n2);

    }

 

    public void TestNullableBoxing()

    {

        int? n = default(int?);         // n = null

        string s = n.ToString();        // s = "";

 

        int? n2 = default(int?);        // n2 = null

        object o = n2 as object;        // Boxing n2. o = null

 

        try

        {

            int? n3 = default(int?);                // n3 = null

            string s3 = (n3 as object).ToString();  // NullReferenceException

        }

        catch (Exception ex)

        {

            Trace.WriteLine(ex.Message);

        }

    }

 

    /// <summary>

    /// Every nullable type can be implicitly converted to any interface that is implemented on the

    /// contained non-nullable type. For example, you can use the IComparable<T> interface with any

    /// numeric nullable type

    /// </summary>

    public void TestNullableBoxing2()

    {

        {

            // A nullable type can be converted to any interface implemented by the contained

            // non-nullable type

            int? n1 = 1;

            int? n2 = 2;

            IComparable<int> nIC = n1 as IComparable<int>;

            int nCompareResult = nIC.CompareTo(n2.Value);

        }

 

        // The following throws a NullReferenceException

        {

            int? n1 = default(int?);

            int? n2 = 2;

            IComparable<int> nIC = n1 as IComparable<int>;      // nIC = null

            int nCompareResult = nIC.CompareTo(n2.Value);       // NullReferenceException is thrown

        }

 

 

    }

}

 

47. Limit Array Parameters to params Arrays

Using array parameters can expose your code to several unexpected problems. It's much better to create method signatures that use alternative representations to pass collections or variable-size arguments to methods.

The problem arises because arrays are covariant as input parameters. In other words, you don't have to pass the exact type of the array into the method. Furthermore, even though the array is passed by value, the contents of the array can be references to reference types. Your method can change members of the array in ways that will not work with some valid types. See TestArrayCovariance1() and TestArrayCovariance2() methods.

Furthermore, because arrays don't support contra variance, when you write array members, your code will fail to compile even though it should. See TestArrayContravariance1() method.

You can avoid those problems by typing parameters as interface types that create a  type-safe sequence to use. Input parameters should be typed as IEnumerable<T> for some T. This strategy ensures that you can't modify the input sequence, because IEnumerable<T> does not provide any methods to modify the collection. Another alternative is to pass types as base classes, a practice that may also avoid APIs that support modifying the collection.

When you need to modify the sequence, it's best to use an input parameter of one sequence and return the modified sequence. When you want to generate the sequence, return the sequence as an IEnumerable<T> for some T.

And yet there are times when you want to pass arbitrary options in methods. That's when you can reach for an array of arguments. But make sure to use a params array. The params array allows the user of your method to simply place those elements as other parameters. See TestParamsArray() method.

To summarize, arrays are not universally wrong method parameters, but they can cause two types of errors. The array's covariance behavior causes runtime errors. Whenever you use an array as a parameter to a method, there is almost always a better alternative. If the parameter represents a sequence, use IEnumerable<T> or a constructed IEnumerable<T> for the proper type. If the parameter represents a mutable collection, then rework the signature to mutate an input sequence and create the output sequence. If the parameter represents a set of options, use a params array. In all those cases, you'll end up with a better, safer interface.

class Item47

{

    /// <summary>

    /// Shows that arrays are covariant; for example, a string[] is a subtype of object[],

    /// therefore, you can pass a string[] when an object[] is expected.

    /// </summary>

    public void TestArrayCovariance1()

    {

        string[] numbers = { "one", "two", "three" };

        TakesAnArray(numbers);

    }

 

    private void TakesAnArray(object[] aData)

    {

        try

        {

            // Assign an integer to aData. This would be possible if aData really were

            // an array of objects, but since it really is an array of strings,

            // we will get an ArrayTypeMismatchException with the following message:

            // "Attempted to access an element as a type incompatible with the array".

            aData[0] = 1;

        }

        catch (Exception ex)

        {

            Trace.WriteLine(ex.Message);

        }

    }

 

    public void TestArrayCovariance2()

    {

        // The following works

        {

            Base[] arr1 = new Base[5];

            FillArray(arr1, () => Base.Factory());

 

            Base[] arr2 = new Base[5];

            FillArray(arr2, () => Derived1.Factory());

 

            Base[] arr3 = new Base[5];

            FillArray(arr3, () => Derived2.Factory());

        }

 

        // The following does not work. There is a mismatch between derived types

        // ArrayTypeMismatchException: "Attempted to access an element as a type

        //incompatible with the array".

        {

            Base[] arr1 = new Derived1[5];

            FillArray(arr1, () => Base.Factory());

 

            Base[] arr2 = new Derived1[5];

            FillArray(arr2, () => Derived1.Factory());

 

            Base[] arr3 = new Derived1[5];

            FillArray(arr3, () => Derived2.Factory());

        }

    }

 

    private void FillArray(Base[] array, Func<Base> generator)

    {

        for (int i = 0; i < array.Length; i++)

            array[i] = generator();

    }

 

    public void TestArrayContravariance1()

    {

        Base[] array = new Base[5];

 

        // Compiler error CS1503: "The best overloaded method match for 'PopulateArray(Derived1[])'

        // has some invalid arguments"

        //PopulateArray(array);

    }

 

    private void PopulateArray(Derived1[] array)

    {

        for (int i = 0; i < array.Length; i++)

            array[i] = new Derived1();

    }

 

    public void TestParamsArray()

    {

        // Calling both DisplayArrayContentsViaArray and DisplayArrayContentsViaParamsArray

        DisplayArrayContentsViaArray( new string[] {"one", "two", "three"} );

        DisplayArrayContentsViaParamsArray("one", "two", "three");

 

        // Note flexibility of using 'params' when no parameters need to be passed

        //DisplayArrayContentsViaArray();                // CS1501: No overload for method 'DisplayArrayContentsViaArray' takes '0' arguments

        DisplayArrayContentsViaArray(new string[] { });  // Note extra syntax!

        DisplayArrayContentsViaParamsArray();            // OK

    }

 

    private void DisplayArrayContentsViaArray(object[] array)

    {

        foreach (object o in array)

            Trace.WriteLine(o);

    }

 

    private void DisplayArrayContentsViaParamsArray(params object[] array)

    {

        foreach (object o in array)

            Trace.WriteLine(o);

    }

}

 

namespace Item47NS

{

    class Base

    {

        public static Base Factory()

        {

            return new Base();

        }

 

        public virtual void DisplayType()

        {

            Trace.WriteLine("Base");

        }

    }

 

    class Derived1 : Base

    {

        public static new Base Factory()

        {

            return new Derived1();

        }

 

        public override void DisplayType()

        {

            Trace.WriteLine("Derived1");

        }

 

    }

    class Derived2 : Base

    {

        public static new Base Factory()

        {

            return new Derived2();

        }

 

        public override void DisplayType()

        {

            Console.WriteLine("Dervied2");

        }

    }

}

48. Avoid Calling Virtual Functions in Constructors

An object is not completely created until all constructors have executed. In the meantime, virtual functions may not behave the way you'd like or expect. Look at TestVirtualInConstructor() method below. What will the output be? Experienced C++ programmers would say, Base::foo. Some C# programmers would say, Constructed in test method. But the correct answer is, Set during initialization.

The base class constructor calls a virtual function that is defined in its class but overridden in the derived class. At runtime, the derived class version gets called. After all, the object's runtime type is Derived. The C# language definition considers the derived object completely available, because all the member variables have been initialized by the time any constructor body is entered. In other words, the variable initializers have executed, but this doesn't mean that you have necessarily initialized all your member variables to the value you want via constructor parameters. Only the variable initializers have executed; none of the code in any derived class constructor body has had the chance to do its work.

Calling virtual functions in constructors works only under the strictest of conditions. The derived class must initialize all instance variables properly in variable initializers. That rules out quite a few objects: Most constructors take some parameters that are used to set the internal state properly. So you could say that calling a virtual function in a constructor mandates that all derived classes define a default constructor, and no other constructor. But that's a heavy burden to place on all derived classes. Do you really expect everyone who ever uses your code to play by those rules?

class Item48

{

    public void TestVirtualInConstructor()

    {

        Derived d = new Derived("Constructed in test method");

    }

}

 

namespace Item48NS

{

    class Base

    {

        protected Base()

        {

            foo();

        }

 

        protected virtual void foo()

        {

            Trace.WriteLine("Base::foo");

        }

    }

 

    class Derived : Base

    {

        private readonly string msg = "Set during initialization";

 

        public Derived(string msg)

        {

            this.msg = msg;

        }

 

        protected override void foo()

        {

            Trace.WriteLine(msg);

        }

    }

 }

49. Consider Weak References for Large Objects

Sometimes you need large blocks of memory for certain algorithms. And sometimes those blocks of memory are needed only occasionally. It seems that you are stuck between two bad alternatives: You could create a local variable, thereby generating a huge heap of garbage every time you run that algorithm. Or you could create a member variable and lock up a large amount of memory for long periods. There are times when neither of those options feels correct.

There is a third option: Create a weak reference (represented in .NET by WeakReference class). Weak references are almost garbage. You tell the garbage collector that an object is ready to be collected, but you keep a handle to it just in case you want it back before it's collected. When you do it correctly, using a weak reference lets you work with the garbage collector, instead of fighting it, to optimize memory usage. Weak references are useful for objects that use a lot of memory, but can be recreated easily if they are reclaimed by garbage collection.

Using a weak reference is simple. You create a new weak reference, telling it to hold on to an object that you are finished using, and then you set the strong reference to null:

WeakReference w = new WeakReference (myLargeObject);
myLargeObject = null;

Now the object referred to by myLargeObject is considered garbage by the system. If the garbage collector runs, it will collect it. However, suppose you need a myLargeObject again before the garbage collector runs. You simply ask WeakReference for the object:

myLargeObject = w.Target as MyLargeClass;
if (myLargeObject == null)
myLargeObject = new MyLargeClass();

The Target property returns null if the object has already been garbage-collected. Then you have no choice except to create a new object. You've off-loaded a very hard optimization problem to the runtime. You get to reuse objects when they are still around, but you let the system reclaim the memory resources when necessary. If the weak reference is reclaimed as a strong reference, it has the same contents and state that it had before. If creating the state is what's expensive, then you should keep a strong reference. A WeakReference is for the case when allocating the memory is expensive.

Also note that objects that implement IDisposable interface are not good candidates for weak references. You have no way of knowing when to call Dispose() on those objects. You cannot know
when you should call Dispose() on an object that you turn into a weak reference.

In practice, weak references help you when you have objects that are very large and are needed only intermittently by an algorithm in your application. Weak references work best for objects that do not need to support IDisposable. Almost by definition, these classes do not have finalizers. Within those constraints, weak references work well to let the garbage collector efficiently manage your memory needs.

This advice must come with a considerable caution and warning: Weak references may make your algorithm work faster, but they also have a large impact on the performance of the garbage collector. Because of that impact, adding weak references to your program may make it much slower. Before you consider weak references, optimize your algorithms. Try to rework them to create less memory pressure overall (see Item 37 Prefer Lazy Evaluation Queries). Only after those approaches have been exhausted should you consider using weak references. Then benchmark your application with  and without weak references, and carefully measure the difference.

class Item49

{

    /// <summary>

    /// Could not get the following example to work

    /// </summary>

    public void TestWeakReference()

    {

        // Create a large object

        MyClass ob = new MyClass();

        ob.MakeSomeGarbage();

 

        // Create a weak reference

        WeakReference wr = new WeakReference(ob, false);

 

        // After creating a weak reference, remove the 'strong reference' that this application has

        // to object 'ob'

        ob = null;

 

        // Garbage collection

        GC.Collect();

 

        // Check weak reference to our large object

        while (wr.IsAlive)

        {               

            //obLarge = (MyClass)wr.Target;

            //strStatus = (obLarge == null) ? "Object is null" : "Object is alive";

            Trace.WriteLine("Object is alive");

 

            System.Threading.Thread.Sleep(1000);

        }

 

        MyClass obLarge = (MyClass)wr.Target;

        string strStatus = (obLarge == null) ? "Object is null" : "Object is alive";

        Trace.WriteLine(strStatus); 

    }

}

 

namespace Item49NS

{

    public class MyClass

    {

        private int[,] matrix = new int[1000, 1000];

        ~MyClass()

        {

            Trace.WriteLine("MyClass Finalized.");

        }

 

        public void MakeSomeGarbage()

        {

            // Create objects and release them to fill up memory with unused objects.

            for (int i = 0; i < matrix.GetUpperBound(0); i++)

                for (int j = 0; j < matrix.GetUpperBound(1); j++)

                    matrix[i, j] = i * j;                       

        }

    }

}

50. Prefer Implicit Properties for Mutable, Nonserializable Data

You can increase the readability of your code by using implicit properties:

public string Name {get; set; }

The compiler creates the backing field using a compiler-generated name. You can even use the property setter to modify the value of the backing field. Because the name of the backing field is compiler generated, even inside your own class you need to call the property accessor rather than modify the backing field directly.

Implicit properties support the same property access specifiers as do their explicit counterparts. You can define any more-restrictive set accessor you need. See class ImplicitProperties1 below.

Of course, because implicit properties generate the same code as explicit properties, you can use implicit properties to define virtual properties, override virtual.  properties, or implement a property defined in an interface. When you create a virtual implicit property, derived classes do not have access to the compiler-generated backing store. However, overrides can access the base property get and set methods just as they can with any other virtual method. See class ImplicitProperties2

You gain two additional advantages by using implicit properties. When the time comes to replace the implicit property with a concrete implementation because of data validation or other actions, you are making binary-compatible changes to your class, and your validation will be in only one location. See classes Person and PersonImproved below.

However, implicit properties have some limitations when it comes to creating immutable types. Even inside your constructor, you must use the property accessor to set the values of your properties. The backing field must support changes, no matter when you call the set accessor. It can't tell the difference between setting the value during construction and setting the value from some other method. This means that your type does not have the initonly flag on the backing field. Furthermore, you could write any mutator methods and have mutator methods sneak into your type. Thus, when you create immutable types, you should use explicit member variables.

The only way to create a true immutable type is to write the properties and backing fields yourself using a concrete implementation. Implicit properties do not support true immutable types at the JIT level.

There is one other important limitation of implicit properties. You cannot use implicit properties on types that are decorated with the Serializable attribute. The persistent file storage format depends on the name of the compiler-generated field used for the backing store. That field name is not guaranteed to remain constant. It may change at any time when you modify the class.

namespace Item50NS

    // Implicit properties support the same property access specifiers as do their explicit

    public class ImplicitProperties1

    {

        public string Name1

        {

            get;

            protected set;

        }

 

        public string Name2

        {

            get;

            internal set;

        }

 

        public string Name3

        {

            private get;

            set;

        }

 

        // etc.

 

        //Error: "Cannot specify accessibility modifiers for both accessors of the property

        // or indexer 'MoreEffectiveCS.Misc.Item50NS.ImplicitProperties.Name4'"

        /*public string Name4

        {

            protected internal get;

            protected internal set;

        }*/

    }

 

    // You can use implicit properties to define virtual properties, override virtual

    // properties, or implement a property defined in an interface.

    public class BaseImplicitProperties

    {

        public virtual string Name

        {

            get;

            protected set;

        }

    }

 

    public class ImplicitProperties2 : BaseImplicitProperties

    {

        public override string Name

        {

            get {return base.Name;}

            protected set

            {

                if (!string.IsNullOrEmpty( value))

                    base.Name = value;

            }

        }

    }

 

    // Implicit properties can be easily replaced with concrete implementations

    public class Person

    {

        public string FirstName { get; set; }

        public string LastName { get; set; }

    }

 

    public class PersonImproved

    {

        private string _strFirstName;

        public string FirstName

        {

            get { return _strFirstName; }

            set

            {

                if (string.IsNullOrEmpty(value))

                    throw new ArgumentException("First name cannot be null or empty");

                else

                    _strFirstName = value;

 

            } 

        }

    }

}