Exercise: Extension methods

In this exercise you will write some extension methods and try to use the methods.

Getting started

Create a new Solution in Visual Studio, type "Console Application". Name the Solution "ExtensionMethods" or something similar.

Create a new class named Helpers (or something similar). This class must be static.

Concat

We often use the static method String.Join(...) to concatenate elements in a List (or a general IEnumerable<T>).

   IList<int> list = new[] { 4, 6, 4, 99, 2, 2 };
   String str = String.Join(", ", list);
   Console.WriteLine(str);

Now, you must make an extension method, called Concat, to simplify the syntax a little

   IList<int> list = new[] { 4, 6, 4, 99, 2, 2 };
   String str = list.Concat(", ");
   Console.WriteLine(str);

The Concat extension method must have a signature like

   public static String Concat<T>(this IEnumerable<T> elements, String separator)

Note that the method is generic.

Create this method and try it out in your Main() method.

Unit test the method

Unit test the Concat method.

Print object

We often use the method Console.WriteLine(...) to print values on the screen.

   String name = "Anders";
   Console.WriteLine(name);

Now you must make an extension method, called Print, to simplify the syntax a little.

   String name = "Anders";
   name.Print();

The Print extension method must have signature like

   public static void Print(this Object obj)

Concat + Print = Nice print of Lists, etc.

The above Print extension method does not work well with List<T> objects and other IEnumerable<T> objects. But if you combine Concat and Print then it works:

   IList list = new[] { 4, 6, 4, 99, 2, 2 };
   list.Concat(", ").Print();

Extra: Act

The Print extension method can be generalized into another method with the signature

   public static void Act(this Object obj, Action<Object> action) 

The action might be Console.WriteLine(...) or something else. Try it!

Print IEnumerable<T>

The above combination of Concat and Print is used so often that we want another version of the Print method that works on IEnumerable<T> objects

Make another Print extension method.

The signature must be like

   public static void Print<T>(this IEnumerable<T> elements, String separator)  

Sorting

To sort Lists of elements we use the method List<T>.Sort()

If we make Sort an extension method It should work on all kinds of IEnumerable<T> object, not only List<T> objects.

Example lines from the Main() method we would like to be able to write:

   String sentence = "My name is Anders"; // String implements IEnumerable<char>  
   sentence.Sort().Print(", ");

Make an extension method Sort with the signature

   public static IEnumerable<T> Sort<T>(this IEnumerable<T> elements) where T : IComparable<T>  

Notice the constraint on the generic type: T must be comparable to another T object.

Implementation steps

  1. Convert the IEnumerable<T> elements to a List. Hint: use the IEnumerable<T> extension method ToList()
  2. Sort the List, using List<T>.Sort()
  3. Return the List object.

Unit test the Sort method

Unit test the Sort method like this

   IList<int> numbers = new[] { 4, 3, 2, 7, 2 };  
   IEnumerable<int> sorted = numbers.Sort();  
   IList<int> expected = new[] { 2, 2, 3, 4, 7 };  
   Assert.IsTrue(expected.SequenceEqual(sorted));

Sorting using Comparison

Sometimes we want to sort IEnumerable<T> objects, even if the element type does not implement IComparable<T>.

In this case we can use the delegate type Comparison<T>.

Make another extension method Sort with signature

   public static IEnumerable<T> Sort<T>(this IEnumerable<T> elements, Comparison<T> comp)  

Implementation steps

  1. Convert the IEnumerable<T> elements to a List.
  2. Sort the List, using List<T>.Sort(comparison)
  3. Return the List object.

Unit test the Sort method

Yes!

Source: GetRandom

The next method you are going to write if formally not an extension method - it is a source method: It produces values.

I want a method that can generate a number of random numbers.

Signature:

   public static IEnumerable<int> GetRandom(int howMany, int max = Int32.MaxValue, int min = 0)  

This method must produce random numbers in the range min ≤ x < max.

Implementation steps:

  1. Make an object of type Random
  2. Make a for loop
  3. Inside the loop produce a new random number, using the method Next(...).
  4. Return the new number using yield return.

Note that max and min have default values. This means that you can call GetRandom with 1, 2 or 3 parameters. If you call with 1 parameters, 2 default values will be used, etc.

In your Main() method you should be able to write

   Helpers.GetRandom(10, 8).Sort().Print(", ");  

Note that since GetRandom is not an extension method, but an ordinary static method, it must be prefixed with the class name (Helpers in this case).

Unit test GetRandom

Unit test the GetRandom: Since you don't know which numbers will be produced you cannot test that hard.

What you can test is

Extra: Unique

After sorting an IEnumerable<T> object we might realize that is has duplicate elements - and we might want to get rid of the duplicates.

Inspiration: The uniq filter (command) from the Unix/Linux operating system.

To do this you must make an extension method with the signature

   public static IEnumerable<T> Unique<T>(this IEnumerable<T> elements)  

It must return the same elements as the input - but skip neighboring duplicate elements.

Implementation (this is a little harder):

In you Main() method you should be able to write

   IList<int> list = new[] { 4, 6, 4, 99, 2, 2, 1 };  
   list.Sort().Unique().Print(", ");  

Unit test

Yes, of course ...

Extra: Unique 2

The Unique relies on the elements having a reliable Equals() method. This is not always the case.

Furthermore it would be nice to eliminate not only duplicates but also other element.

How about the following:

   list.Unique((i, j) => i < j).Print(", ");  

Is must eliminate all element which are not higher than the previous element ((i, j) => i < j). Note that list in this case is of type int.

Make another extension method Unique with the signature:

   public static IEnumerable<T> Unique<T>(this IEnumerable<T> elements, Func<T, T, bool> tester)  

Unit test

Yes ...

Extra: Split

Inspiration: The C# Partitioner class.

I want a method that can split an IEnumerable<T> object into a number of IEnumerable<T> elements (chunks). All chunks should have the same chunk size, except for the last chunk which might be smaller.

Make an extension method with the signature

   public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> elements, int chunkSize)  

This method might have been useful in the Password Cracking exercise, at least for some of the architectures.

Implementation: Requires some thinking, but not that many lines ...

Unit test

As always.