Quantcast
Channel: C# – Falafel Software Blog
Viewing all articles
Browse latest Browse all 54

nameof – Day 3 – VS 2015 Series

$
0
0

When magic isn’t

Discernng why certain code is considered good and other code -well- isn’t is often readily apparent by examing a handful of the code’s characteristics.
One important characteristic which is always considered is the code’s level of coupling.

Various parts of a system are “coupled” if they interact therefore depend on each other. If the interdependencies are limited to what is strictly -and practically- necessary the system is considered loosely coupled, this is good practice. The opposite extreme is considered tightly coupled, bad code smell, and to be avoided. Most code is somewhere in between.

This post is about addressing a particular case of tight coupling, one with a potential for generating run-time errors, and a language addition in C# 6 which can help with such cases, namely nameof.

Too often we find ourselves having to use a “magic string.” A magic string is a hard-coded string whose value is used to determine specific functionality. Magic Strings are a form of tight coupling; one which can typically not be validated before run-time.

Here’s a simple Magic String, “MyBackDoor”:

public User Login(string userName, byte[] password)
{
    if (userName == "MyBackDoor")
    {
        return GetSuperAdmin();
    } else {
        return validateLogin(userName, password)
    }
}

A more common example are cases where the alternative is convoluted reflection. This example includes the current class, method, and method parameter identifiers (names) as part of an exception message.

void Main()
{
    var result = NameOfClass.DivByParamMagic(1);
    Console.WriteLine(result);
    result = NameOfClass.DivByParamMagic(0);
    Console.WriteLine(result);
}

public static class NameOfClass
{
    public static string DivByParamMagic(int paramName)
    {
        try
        {
            int result = 42 / paramName;
            return String.Format("The answer is {0}", result);
        }
        catch (Exception ex)
        {
            string msg = String.Format("An error occurred in the {0} method of {1} with {2} = {3}. Error message: {4}", 
                    "DivByParamMagic",   // method identifier
                    "NameOfClass",       // class identifier
                    "paramName",         // method parameter identifier
                    paramName,           // value of method parameter
                    ex.Message);
            throw new Exception(msg);
        }

    }
}

Output:
"The answer is 42"
"An error occurred in the DivByParamMagic method of NameOfClass with paramName = 0. Error message: Attempted to divide by zero."

This code works fine, we’ve all seen if not written similar. Nonetheless, it’s worrisome.
What happens if we refactor the method? To illustrate let’s change the class name to Math, the method to DivByParam, and the parameter paramName to something a bit more descriptive, intParam.

void Main()
{
    var result = MyMath.DivByParam(1);
    Console.WriteLine(result);
    result = MyMath.DivByParam(0);
    Console.WriteLine(result);
}

public static class MyMath
{
    public static string DivByParam(int intParam)
    {
        try
        {
            int result = 42 / intParam;  // changed from paramName
            return String.Format("The answer is {0}", result);
        }
        catch (Exception ex)
        {
            string msg = String.Format("An error occurred in the {0} method of {1} with {2} = {3}. Error message: {4}",
                    "DivByParamMagic",  // method identifier
                    "NameOfClass",     // class identifier
                    "paramName",       // method parameter identifier
                    intParam,          // value of method parameter
                    ex.Message);
            throw new Exception(msg);
        }

    }
}
Output:
"The answer is 42"
"An error occurred in the DivByParamMagic method of NameOfClass with paramName = 0. Error message: Attempted to divide by zero."

In order to compile we had to change two references in the method body from paramName to intParam. However, nothing clued us to the fact the magic strings no longer being sound and our error result has become misleading.

Enter nameof()

nameof() provides a refactor-safe way of getting the name of a parameter, member, or type.

Here’s our original method rewritten to use nameof():

public static string DivByParamMagic(int paramName)
{
    try
    {
        int result = 42 / paramName;
        return String.Format("The answer is {0}", result);
    }
    catch (Exception ex)
    {
        return String.Format("An error occurred in the {0} method of {1} with {2} = {3}. Error message: {4}", 
                nameof(DivByParamMagic), // method identifier
                nameof(NameOfClass),     // class identifier
                nameof(paramName),       // method parameter identifier
                paramName,               // value of method parameter
                ex.Message);
    }
}

After we refactor we won’t be able to compile this method until we update the three references.

public static string DivByParam(int intParam)
{
    try
    {
        int result = 42 / intParam;  // changed
        return String.Format("The answer is {0}", result);
    }
    catch (Exception ex)
    {
        string msg = String.Format("An error occurred in the {0} method of {1} with {2} = {3}. Error message: {4}",
                nameof(DivByParam), // changed from DivByParamMagic
                nameof(MyMath),     // changed from NameOfClass
                nameof(intParam),   // changed from paramName
                intParam,           // changed from paramName
                ex.Message);
        throw new Exception(msg);
    }
}
Output:
"The answer is 42"
"An error occurred in the DivByParam method of MyMath with intParam = 0. Error message: Attempted to divide by zero."

When all is said and done nameof() provides us a simple and relatively safe way to access various program element identifiers.

 

The post nameof – Day 3 – VS 2015 Series appeared first on Falafel Software Blog.


Viewing all articles
Browse latest Browse all 54

Trending Articles