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

Introduction

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.

What is Yield Keyword?

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.

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.

Example

class Employee
{
    public string Name { get; set; }
    public int Salary { get; set; }
}

class Program
{
    static List<Employee> Employees = new List<Employee>
    {
        new Employee { Name = "Tom", Salary = 12000 },
        new Employee { Name = "Harry", Salary = 15000 },
        new Employee { Name = "Sam", Salary = 10000 },
        new Employee { Name = "Mike", Salary = 25000 },
        new Employee { Name = "Bob", Salary = 22000 },
        new Employee { Name = "Raj", Salary = 18000 },
    };

    static void Main(string[] args)
    {
        PrintData();
    }

    static void PrintData()
    {
        foreach (var emp in FilterWYield())
        {
            Console.WriteLine(emp.Name);
        }

        foreach (var emp in FilterSimple())
        {
            Console.WriteLine(emp.Name);
        }
    }

    static IEnumerable<Employee> FilterWYield()
    {
        foreach (var item in Employees)
        {
            if (item.Salary >= 20000)
            {
                yield return item;
            }
        }
    }

    static IEnumerable<Employee> FilterSimple()
    {
        List<Employee> emps = new List<Employee>();
        foreach (var item in Employees)
        {
            if (item.Salary >= 20000)
            {
                emps.Add(item);
            }
        }
        return emps;
    }
}

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.

What is String Interning?

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 Lazy<T>?

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 Lazy<T>?

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.

Example

Lazy<TimeSheet> objTimeSheet = new Lazy<TimeSheet>();
Lazy<Appraisal> objAppraisal = new Lazy<Appraisal>();
Lazy<Performance> objPerformance = new Lazy<Performance>();

if (TimeSheetRequested)
{
  ShowTimeSheet(objTimeSheet.Value.CurrentWeek);
}

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

What is WeakReference?

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.

Example

{
    // Instantiation of VeryLargeObject
    VeryLargeObject objLarge = new VeryLargeObject();

    // Creating a weak reference for VeryLargeObject
    WeakReference weakReference = new WeakReference(objLarge);

    // Setting VeryLargeObject to null
    objLarge = null;

    // Checking if weak reference is garbage collected
    if (weakReference.IsAlive)
    {
        // Reclaiming from weak Reference
        VeryLargeObject objLargeNew = weakReference.Target as VeryLargeObject;
    }
}

This is a complete tutorial on MSDN about C# WeakRefernce

What is Immutable in C#?

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.

What is T: Type in C#?

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

When to use T:Type?

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

Example

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

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

Less Popular Operators

1. Null-Coalescing Operator (??)

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

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

It also supports chaining

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

2. @ Operator

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

var @object = new object();
var @string = "";
var @if = isValidEmailId("[email protected]");

3. Properties initialization

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

private static int _age;

public static int Age
{
    get
    {
        return _age;
    }

    set
    {
        _age = value;
    }
}

above code segment is equivalent to below code segment.

public static int age { get; set; } = 10;

4. Namespace Aliasing

using System.Windows.Forms;
using System.Web.UI.WebControls;
using PC.Project.BusinessLogic.Validation;

class A
{
    void Method()
    {
        // Use the alias
        Validation.DataValidator dataValidator = new Validation.DataValidator();
    }
}

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.

class ClassA
{
}

class ClassB : ClassA
{
}

class ClassC
{
}

static void Main(string[] args)
{
    ClassA objA = new ClassA();
    ClassB objB = new ClassB();
    ClassC objC = new ClassC();

    Console.WriteLine(objA is ClassB); // Output: False
    Console.WriteLine(objB is ClassA); // Output: True
    Console.WriteLine(objC is ClassA); // Output: False

    Console.WriteLine(objA as ClassB); // Output: True
    Console.WriteLine(objB as ClassA); // Output: True
    Console.WriteLine(objC as ClassA); // Output: NullReferenceException
}

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

Originally published at taagung.


Similar Articles