The Top Seven Least-Known, Yet Important, C# Features

We could be an experienced programmer who has been coding since long in C#. Still, there are a few C# language features which we don’t use frequently and probably know very little about them. I have listed down 7 most underutilized features of C# in this article ahead. So, let's start.

Yield Keyword

What is this?

In my list, Yield gets the first position of unsung C# features. It maintains the state in the loop and returns back to the calling method and resumes with the previous state, i.e., Yield provides Stateful Iteration.

If you don’t understand this statement, don’t worry and don’t give up; you will be having a very good understanding of this in the next 2 minutes.

To understand that, let us explore this code and its explanation.

Code Example

Use Case

Here, I want to print the employee names who are having a salary more than 20,000. I am using the in-memory collection.

  1. class Employee  
  2. {  
  3.      public string Name { getset; }  
  4.      public int Salary { getset; }  
  5. }  
  7. class Program  
  8. {
  9.     static List<Employee> Employees = new List<Employee>()  
  10.     {  
  11.         new Employee{ Name="Tom", Salary=12000},  
  12.         new Employee{ Name="Harry", Salary=15000},  
  13.         new Employee{ Name="Sam", Salary=10000},  
  14.         new Employee{ Name="Mike", Salary=25000},  
  15.         new Employee{ Name="Bob", Salary=22000},  
  16.         new Employee{ Name="Raj", Salary=18000},  
  17.      };  
  19.      static void Main(string[] args)  
  20.      {  
  21.              PrintData();  
  22.      }  
  24.      static void PrintData()  
  25.      {  
  26.          foreach (var emp in FilterWYield())  
  27.          {  
  28.              Console.WriteLine(emp.Name);  
  29.          }  
  31.          foreach (var emp in FilterSimple())  
  32.          {  
  33.              Console.WriteLine(emp.Name);  
  34.          }  
  35.      }  
  38.      static IEnumerable<Employee> FilterWYield()  
  39.      {  
  40.          foreach (var item in Employees)  
  41.          {  
  42.              if (item.Salary >= 20000)  
  43.                  yield return item;  
  44.          }  
  45.      }  
  47.      static IEnumerable<Employee> FilterSimple()  
  48.      {  
  49.          List<Employee> emps = new List<Employee>();  
  50.          foreach (var item in Employees)  
  51.          {  
  52.              if (item.Salary >= 20000)  
  53.                  emps.Add(item);  
  54.          }  
  55.          return emps;  
  56.      }  
  57.  }  

Code Explanation


For the simple implementation in FilterSimple() method, I have used a temporary collection (emps). When the condition (Salary >=20000) gets true, it adds that item to the this collection (emps) and at the end of execution of foreach loop, it returns that collection to caller methods PrintData() and prints the result.

Implementation with Yield is different. We do NOT need additional collection in FilterWYield(). In the foreach loop, it evaluates the condition and when the condition (Salary >=20000) is true, it returns the value to the caller method PrintData() and prints the result. Then, again, it comes back to FilterWYield() method and resumes the execution (Note here - it doesn't start, rather remembers the position in collection and resumes from there only). That is why it is called as Stateful Iteration.

This diagram explains the scenario in a better way.

As you can see here, for Tom, Harry, and Sam, the loop executes normally and checks from the condition which is false and execute next.

Top 7 Least Known But Important C# Features 

For Mike, the condition evaluates to true and then it passes the value to PrintData() where it prints the name of the employee as Mike. Now, it comes back to the collection and resumes where it had left, i.e., now it will execute the condition for Bob and again it is true and takes the data to PrintData() method and prints the name, Bob. It comes back to the collection and resumes execution of condition for Raj and condition fails and doesn't go to the PrintData() method and loop ends.

I hope with this, you understand the working on Yield and why it provides Stateful Iteration. For more details, please refer to this MSDN article.

String Interning

What is this?

When we assign a value to a string variable at run time, it creates a new instance of that. If we already have that value in memory, then also, it will create a new instance, instead of using that.

With string interning, we can ask the compiler to use the existing memory reference and abandon any other string variable having the same value.

In this article, I have explained everything from basic to the advanced level we need to know about string interning and how to use in your real time project. 


What is this?

Lazy Instantiation enables object creation when it is used for the first time. It is used from performance and unnecessary computation when they are not actually needed.

When to use?

This could be useful when a large object is needed but they are accessed later.

Use Case

I have one employee class which has information about his Project, Manager, Performance, Appraisal, Timesheet, and other related data. For those values, it needs to call a few services and database as well. On my employee page, I need to show the Manager and Project information but not his performance and timesheet related data. If the user wishes to open those sections, then only we will show those data.

In this case, we can enable Lazy Instantiation for Timesheet, Performance, and Appraisal related information. 

Code Implementation

  1. Lazy<TimeSheet> objTimeSheet = new Lazy<TimeSheet>();  
  2. Lazy<Appraisal> objAppraisal = new Lazy<Appraisal>();  
  3. Lazy<Performance> objPerformance  = new Lazy<Performance>();  
  4. if (TimeSheetRequested)  
  5. {  
  6.     ShowTimeSheet(objTimeSheet.Value.CurrentWeek)  
  7. }  

More Study

Read this MSDN article to get more in depth and understanding of Lazy loading.


What is this?

By default, in C#, all reference types are strong referenced i.e. When they are NOT being referenced in the program, they will be garbage collected. By definition, WeakRefernce allows the object to be garbage collected.

When to use WeakReference?

It is suitable for large memory using classes. If we are not using that part of the application, then we can make this class as WeakReference and later, we can reclaim it. It has one risk involved - when the class has been garbage collected, it will NOT be possible to recreate the object.

Code Example

  1. {  
  2.     //Instatantiation of VeryLargeObject  
  3.     VeryLargeObject objLarge = new VeryLargeObject();  
  4.     //Creating a weak reference for VeryLargeObject           
  5.     var weakReference = new WeakReference(objLarge);  
  6.     //Setting VeryLargeObject to null  
  7.     objLarge = null;         
  8.     //Checking if weak reference is garbage collected        
  9.     if(weakReference.IsAlive)  
  10.     {  
  11.         // Reclaiming from weak Reference   
  12.         VeryLargeObject objLargeNew  = weakReference.Target as VeryLargeObject;  
  13.     }  
  14. }  

More Study

This is a complete tutorial on MSDN about C# WeakRefernce


From C# language, we don’t get it as a language feature but we can implement it using const and static. It is an important feature so I have included this to my list.

Immutable classes can be used as a class which doesn’t change its state at any point of existence. They can be very useful in a multithreaded environment which requires less validation. My article on immutable classes in C# has everything you need to know about it.

Where T: Type

What is this?

This constraint informs C# compiler about the type arguments. Without constraint, it may apply any type or by default System.Object.

When to use?

When we want a certain restriction on the implementation in our generic class or collection. This can be applied to Struct, class, Enum, Interface.

Code example

  1. class BlogContribution<T> where T : Article, Blog, IArticle, Videos System.IEnumerable<T>, new()  
  2. {  
  3.     // ...  
  4. }  

More Study

This MSDN article has all the details we need to know about these constraints.

Less Popular Operators

7.1 - Null-Coalescing Operator (??)

It will return the left-hand operand if that is not null else will return the right-hand operand.

  1. String name = dbReader.Name?? “Not found”  

It also supports chaining

  1. string result = value1 ?? value2 ?? value3 ?? String.Empty;  

7.2 - @ Operator

It let us name the variable same as C# language reserved keywords, as it is shown here.

  1. var @object = new object();  
  2. var @string = "";  
  3. var @if = isValidEmailId("");   

7.3 - Properties initialization

This works as a short cut to assign default value to any property, as shown below,

  1. private static int _age;  
  2. public static int Age  
  3. {  
  4.     get { return _age = 10; }  
  5.     set { value = _age;}

above code segment is equivalent to

  1. public static int age { getset; } = 10;  

7.4 - Namespace Aliasing

  1. using win = System.Windows.Forms;  
  2. using web = System.Web.UI.WebControls;  
  3. using Validation = PC.Project.BusinessLogic.Validation;  
  4. class A  
  5. {  
  6.     void Method()  
  7.     {  
  8.         // Use the alias  
  9.         Validation.DataValidator dataValidator = new Validation.DataValidator();  
  10.     }  
  11. }  

7.5 - As and Is

Is operator is used to see if run-type of an object is compatible with another type. While as operator is used to convert one type to another.

  1.  class ClassA { }  
  2.  class ClassB : ClassA { }  
  3.  class ClassC { }  
  5.  static void Main(string[] args)  
  6.  {  
  7.      ClassA objA = new ClassA();  
  8.      ClassB objB = new ClassB();  
  9.      ClassC objC = new ClassC();  
  11.      Console.WriteLine(objA is ClassB); // Output : False  
  12.      Console.WriteLine(objB is ClassA); // Output : True  
  13.      Console.WriteLine(objC is ClassA); // Output : False  
  15.      Console.WriteLine(objA as ClassB); // Output : True  
  16.      Console.WriteLine(objB as ClassA); // Output : True  
  17.      Console.WriteLine(objC as ClassA); // Output : Exception  
  18. }  

With this, I hope you understand the underrated features of C# and use them in your project.

Originally published at taagung.