What if I told you that 5 easy tips from a senior C# developer can make you an better coder? Would you believe me?
Most people won’t, because we tend to assume that skill and experience are innate traits that only the most talented developers are born with.
While that may be partially true, when it comes to being able to develop software, most of what makes an exceptional coder doesn’t come down to natural talent as much as it does deliberate practice and some critical thinking skills.
These tips are provided by Stefan Djokic, Senior Software Engineer working at EXLRT, a digital customer experience agency specializing in retail, travel and hospitality working with huge companies such as Adidas, IBM or Disneyland Paris.
I very recommend you to follow him on Linkedin because he is always sharing valuable content about C#, .NET and more!
Use yield whenever you can
In the first tip revealed by Stefan, he comments that developers usually use temporary variables to store collection elements when using loops to create a new collection of elements.
Let’s check his code example:
List<int> tempResult = new();
foreach(var item in collection)
{
tempResult.Add(item);
}
return tempResult;
In this case Stefan recommends using yield return as it will provide a statefull and custom iteration:
“Control is returned to the caller each time the “yield return” statement is encountered and executed.”
Followed by this, he added:
“Most importantly, with each such call, the callee’s state information is preserved so that execution can continue immediately after the yield statement when the control returns.”
And his result is as follows:
foreach(var item in collection)
{
yield return item;
}
Lastly, he commented on some notes to always keep in mind, in his own words:
– We cannot use the “yield return” or the “yield break” statements inside anonymous & unsafe methods
– The return type of the method where we are using yield, should be IEnumerable or IEnumerator.
– We cannot use the yield return statement in a try-catch block though we can have it inside a try-finally block
Keep this in mind developers. Here is the original link to Stefan’s tip: Use yield whenever you can.
Get iteration index in foreach loop
For this second tip, Stefan talks about best practices for track indices and throws out a question:
“How to get the index of the current iteration of a foreach loop?”
Following this, he himself answered this question to clarify the doubts for all of us:
“The easiest way to track indices is to set the index variable in front of the loop and increase it in each iteration — just like working in a while loop.”
And the scenario he proposes is as follows:
foreach (var (value, i) in users.Select((value, u) => (value, i)))
{
User value = user.value;
int index = user.i;
}
Having made this clear, Stefan goes on to pose a scenario in which this is achieved without using a variable.
This is possible, combining the Select()
LINQ method and ValueTuple
, but Stefan comments that this is not his favorite way and details the reasons:
1. Reduced code readability
2. Worse performance (space & time expenses)
3. Difficult to maintain
4. Just why?
Just why? By now I’m sure some of you have asked yourself this question.
That is why Stefan reveals the best way to get the index of an iteration of a foreach loop:
“ – Use for loop (if you can)
– Use MoveNext() & Current property”
Another good tip to improve 1%, remember that success is in perseverance. Here is the original link to Stefan’s tip: Get iteration index in foreach loop.
Don’t use ‘+’ string concatenation in loops
Loops in C# are the focus of this third tip, Stefan warns that it’s not good practice use +
string concatenation.
This is because a string is immutable, as Stefan himself comments:
“Once we create a string, it cannot be changed.”
In order to better understand this, this great senior developer has given a practical example:
– We have a new “Test” string — This string will take up memory space on the Heap.
– We change the original string to “Test for string”.
– We will create a new string object on the Heap.
– Instead of modifying the original string at the same memory address.
The code excerpt looks like this:
string finalStr = "";
foreach (var str in stringArray)
{
finalStr = finalStr + str;
}
If you are curious to know what happens when you do it this way, the main thing is the possible loss of performance.
Why? Because multiple memory allocations would be used when modifying a string multiple times.
Stefan’s favorite solution to this problem is to use StringBuilder
. As he states:
“The ‘
StringBuilder'
doesn’t create a new object in the memory but dynamically expands memory to accommodate the modified string.”
With your solution in mind, the above code example would look flawless as follows:
StringBuilder builder = new StringBuilder();
foreach( var str in stringArray)
{
builder.Append(str);
}
string finalStr= builder.ToString();
Finally, Exlrt’s Software Engineer poses a question to all developers:
Do you have a + concatenation in the loop somewhere in the code?
Have you encountered this problem in a real-world situation?
Both Stefan and I would like to know if this has ever happened to you and if you have personally noticed any problems.
Here is the original link to Stefan’s tip: Don’t use ‘+’ string concatenation in loops
Sealed Classes
The frog with 6 legs is the name Stefan has given to the story of his fourth tip.
You might be wondering since when did a frog have six legs, right🐸? Well, let Stefan tell you the mini story he came up with:
A: Why do you have a MyFrog class, when there is a standardized Frog class? Also, your frog has six legs?? 😮
B: Haha, so you let me have it. 😅
A: How to?
B: You let me extend your standardized frog with extra legs. You allowed me to inherit your class.
A: I should have used the sealed keyword. 🤦♂️
If Stefan would make an advanced C# book using this kind of mini example stories and his way of explaining things, I’m sure it would be the best acquisition of my life and the book would be a success in general (you know Stefan😉).
Back to the tip, the main reason (among several others that we will see later) why using Sealed classes is much more appropriate is to restrict the inheritace feature.
Alongside this, he states:
“Once we define a class as a sealed class, we cannot inherit it anymore.”
Another guideline he adds in this tip is that on a method or property that overrides a virtual method or property in a base class, we may also use the sealed keyword.
This prevents other classes from overriding certain virtual methods or attributes while still enabling them to inherit from the base class.
And if you are wondering what are the advantages of using sealed classes, these are the 3 points mentioned by the Software Engineer:
1. Take away the inheritance feature from the class users so they cannot derive a class from it.
2. Best when we have a class with static members.
3. Can lead to improved performances
Let’s look at Stefan’s example!
sealed class Users
{
public string name = "Stefan Djokic";
public void GetName()
{
Console.WriteLine("Name: {0}", name);
}
}
//Derived Class
public class Details : users //Error
{
public int age = 27;
public void GetAge()
{
Console.WriteLine("Age: {0}", age);
}
}
Here is the original link to Stefan’s tip: Sealed Classes
Select() vs SelectMany()
For this fifth tip, Stefan has decided to share with us a customer case study.
To quickly put us in his scenario:
“The client has requested all the technologies that your employees know.
…we have a class Employee with the name of the employee and a list of technologies he knows how to work”
This is how the scenario is presented:
List<Employee> employees = new();
Employee emp1 = new Employee { Name = "Stefan", Skills = new List<string> {"C", "C++", "Java"}};
Employee emp2 = new Employee { Name = "Karan", Skills = new List<string> {"SQL Server", "C#", "ASP.NET"}};
Employee emp3 = new Employee { Name = "Lalit", Skills = new List<string> {"C#", "ASP.NET MVC", "Windows Azure", "SQL Server"}};
employees.Add(emp1);
employees.Add(emp2);
employees.Add(emp3);
Now, to solve the challenge proposed by his client, the Software Engineer has come up with two solutions:
.Select()
.SelectMany()
First of all, Stefan has proposed the supposed scenario with .Select()
:
IEnumerable<List<String>> resultSelect = employees.Select(e=> e.Skills);
foreach (List<String> skillList in resultSelect)
{
foreach (string skill in skillList)
{
Console.WriteLine(skill);
}
}
Let’s quickly see what Stefan tells us about this way of doing it:
1. We are using 2 loops.
2. The first loop goes through all the employees.
3. The second loop goes through all the skills of each employee.
With this in mind, let’s see what the assumed scenario would look like if we were to use .SelectMany()
:
IEnumerable<string> resultSelectMany = employees.SelectMany(emp => emp.Skills);
foreach (string skill in resultSelectMany)
{
Console.WriteLine(skill);
}
Just at first glance we can see that the resulting code is shorter using .SelectMany()
compared to .Select()
.
If done with .SelectMany()
, as Stefan reports, the process varies:
1. We are getting the list of the skills immediately.
2. The first and only loop goes through the skills of each employee.
This way we can save 1 loop, which will compensate us in terms of performance.
Finally, he adds another small but good option to consider:
“We can use ‘SelectMany’ to “flatten” a nested or tiered collection into a simple single-tier collection.”
Here is the original link to Stefan’s tip: Select() vs SelectMany()
Thanks again to Stefan Djokic for sharing these tips and bringing value to the great and wonderful community of .NET developers. If you liked them I would recommend you to follow him on Linkedin because he is always active and uploads a lot of valuable .NET content!