The nameof expressions
The nameof
expressions are particularly nice. You can now provide a string that names an object in code. This is especially handy if you are throwing exceptions. You can now see which variable caused the exception. In the past, developers had to rely on messy string literals in their code. This was particularly error prone and vulnerable to spelling errors. Another problem was that any code refactoring might miss a string literal, and then that code becomes obsolete and broken.
The nameof
expressions have come to save the day. The compiler will see that you are referencing the name of a specific variable and correctly convert it to a string. nameof
expressions, therefore, also stay in sync with any refactoring you may do.
Getting ready
We will use the same code example that we wrote in the String interpolation recipe from this chapter, with a few small changes. We will create a Student
object and add students to it. We will then return that object to the console and output the student count.
How to do it…
- Create a class called
Recipe5NameofExpression
. Add an auto-implemented property to this class calledStudentCount
:public static class Recipe5NameofExpression { public static int StudentCount { get; set; } = 0; }
- Next, we need to add the
GetStudents
method, which returns aList<Student>
object. The method contains atry
/catch
statement and will throwArgumentNullException()
:public static List<Student> GetStudents() { List<Student> students = new List<Student>(); try { Student st = new Student(); st.FirstName = "Dirk"; st.LastName = "Strauss"; st.JobTitle = ""; st.Age = 19; st.StudentNumber = "20323742"; students.Add(st); st.FirstName = "Bob"; st.LastName = "Healey"; st.JobTitle = "Lab Assistant"; st.Age = 21; st.StudentNumber = "21457896"; students.Add(st); //students = null; StudentCount = students.Count(); return students; } catch (Exception ex) { throw new ArgumentNullException(nameof(students)); } }
Note
In reality, we would not simply return
ArgumentNullException
off the bat like that. This is simply being used to illustrate the concept of thenameof
expression as used inArgumentNullException
. - In the console application, we will add code that returns the
List<Student>
object and reports how many students were contained in the list by outputting theStudentCount
property value to the console window:try { List<Chapter1.Student> StudentList = Chapter1.Recipe5NameofExpression.GetStudents(); Console.WriteLine($"There are {Chapter1.Recipe5NameofExpression.StudentCount} students"); } catch (Exception ex) { Console.WriteLine(ex.Message); } finally { Console.Read(); }
How it works…
Running the console application with the code as is will call the GetStudents()
method. This will then create the List<Student>
object and add two Student
objects to it. The StudentCount
property is set equal to the count of the List<Student>
object. The GetStudents()
method then returns the result to the console application, which then reads the StudentCount
property and displays it in the console output:
If we now went ahead and modified the code in the GetStudents()
method to set the students
variable to null
right before we called students.Count()
, an exception would be thrown. The exception is caught in catch
, and this is where we use the nameof
expression to display a string literal of the students
variable:
Using the nameof
expression, we can ensure that the expression stays in sync with refactoring actions such as renaming the students
variable:
If we had written the code in the catch
statement using a string literal, we would not have had the code updated automatically when we renamed the students
variable. The nameof
expression effectively allowed developers to stop writing throw new ArgumentNullException("students");
, which will not be affected by refactoring actions.
Another benefit of using a nameof
expression in your code is that it involves no runtime cost, because the code containing the string literal is generated at compile time.
Modify the code in the console application slightly to make it look like this:
List<Chapter1.Student> StudentList = Chapter1.Recipe5NameofExpression.GetStudents(); int iStudentCount = Chapter1.Recipe5NameofExpression.StudentCount; Console.WriteLine($"The value of the { nameof(Chapter1.Recipe5NameofExpression.StudentCount)} property is {iStudentCount}");
When you run your console application now, you can see that the nameof
expression has been used to create the string literal of the StudentCount
property:
Note
Ensure that you have commented out the students = null
; line of code in the GetStudents()
method; otherwise, you will still receive the null exception.
You can also use the nameof
expression with enumerators. Add the following code to your class. We are basically creating an enumerator called Course
. In the SetCourse()
method, we set a course based on a course ID:
public enum Course { InformationTechnology = 1, Statistics = 2, AppliedSciences = 3 } public static string SelectedCourse { get; set; } public static void SetCourse(int iCourseID) { Course course = (Course)iCourseID; switch (course) { case Course.InformationTechnology: SelectedCourse = nameof(Course.InformationTechnology); break; case Course.Statistics: SelectedCourse = nameof(Course.InformationTechnology); break; case Course.AppliedSciences: SelectedCourse = nameof(Course.InformationTechnology); break; default: SelectedCourse = "InvalidCourse"; break; } }
We then use a switch
statement to select the course defined by the course ID parameter and set the SelectedCourse
property equal to the nameof
expression of the enumerator. Add the following code to your console application:
Chapter1.Recipe5NameofExpression.SetCourse(1); Console.WriteLine($"The selected course is { Chapter1.Recipe5NameofExpression.SelectedCourse}");
Running the console application will result in the string representation of the selected enumerator value:
The nameof
expression is a very good way of keeping your code in sync when dealing with the string literals of objects in C# 6.0.