I start reading "More Effective C# from Bill Wagner". It is a really nice book, unlike the other books i read, with this book i start reading random chapters. Actually not that random, the chapters that i like more :) I will highly recommend this book btw.
So lets take a look at the Item 17: Create Composable APIs for Sequences
here is a simple code from the book:
public static void Unique(IEnumerable<int>num)
{
Dictionary<int,int>uniqueVals = new Dictionary<int,int>();
foreach(int num in nums)
{
if(!uniqueVals.ContainsKey(num))
{
uniqueVals.Add(num,num);
Console.WriteLine(num);
}
}
}
So what's wrong with the code above? First of all, the code is writing the unique numbers to the console on a passed IEnumerable<int>. However, the function is doing more than 1 principal job, it does 2 different things. First it loops through the numbers, collects the unique numbers in a dictionary, and second, it writes the numbers to the console. Because of 2 unrelated jobs being assigned to this function, it is not easy to reuse the code, and also not easy to unit test the code. If you could seperate this 2 jobs into 2 different functions, it will be easier to unit test this code and also reuse this code. Let's try to do refactor code as step 1 progress:
public static Dictionary<int,int> Unique(IEnumerable<int>num)
{
Dictionary<int,int>uniqueVals = new Dictionary<int,int>();
foreach(int num in nums)
{
if(!uniqueVals.ContainsKey(num))
{
uniqueVals.Add(num,num);
}
}
return uniqueVals;
}
private static void PrintUniques(IEnumerable<int>numbers)
{
Dictionary<int,int>uniqueVals = Unique(numbers);
foreach(int num in uniqueVals )
{
Console.WriteLine(num);
}
}
Now we divided the function into 2 functions, and they can be easily reused as they only do 1 task, also it is easier to unit test it (to unit test PrintUniques function, you can use StreamWriter instead of console). However we can easily refactor this code more :), using "yield". Yield is an interesting function, it returns the value while you are iterating one at a time. One big advantage is you dont have to load the whole array into the memory, so if in any part of your loop, you have an exit from the iteration, you wont end up having everything loaded in the memory and not using it :) So you will get the value, and the index pointer will move to the next element, for the next step in the iteration. This is kinda like lazy loading in LINQ. Here is the code again:
public static IEnumerable<int> Unique(IEnumerable<int>num)
{
Dictionary<int,int>uniqueVals = new Dictionary<int,int>();
foreach(int num in nums)
{
if(!uniqueVals.ContainsKey(num))
{
uniqueVals.Add(num,num);
yield return num;
}
}
}
private static void PrintUniques(IEnumerable<int>numbers)
{
foreach(int num in Unique(numbers))
{
Console.WriteLine(num);
}
}
Hope it is clear and easy to understand. Let me know if you have any questions.