#1,209 – C# 6.0 – Using the nameof Operator

C# 6.0 adds a nameof operator that accepts the name of some program element and returns a string representing the name of the element.  The nameof operator can take as a parameter:

  • Class names
  • Class members
  • Method names
  • Variables

Below, the ShowoffNameof method reports the names of various program elements within the Dog class.  This avoids having to explicitly use reflection to access the names of things.

    public class Dog
    {
        public string Name { get; set; }

        public Dog(string name)
        {
            Name = name;
        }

        public string ShowoffNameof(int myInteger, string myString)
        {
            StringBuilder sbOut = new StringBuilder();

            sbOut.AppendLine(string.Format("Class: {0}", nameof(Dog)));
            sbOut.AppendLine(string.Format("Method: {0}", nameof(ShowoffNameof)));
            sbOut.AppendLine(string.Format("Name prop: {0}", nameof(Name)));
            sbOut.AppendLine(string.Format("1st param: {0}", nameof(myInteger)));
            sbOut.AppendLine(string.Format("2nd param: {0}", nameof(myString)));
            sbOut.AppendLine(string.Format("Local variable: {0}", nameof(sbOut)));

            return sbOut.ToString();
        }
    }

Here’s the output:
1209-001

Advertisement

#1,208 – C# 6.0 – Auto-Property Initializers Can Be Any Expression

An auto-property initializer, used to initialize the value of an auto-implemented property, can be any expression.  This includes the result of a method call.

Below, we initialize the value of the SecretName property to a value returned by the static function generateSecreteName.

    public class Dog
    {
        public string Name { get; set; }

        // DogCreationTime is immutable
        public DateTime DogCreationTime { get; } = DateTime.Now;

        public string SecretName { get; } = generateSecretName();

        public Dog(string name)
        {
            Name = name;
        }

        private static string generateSecretName()
        {
            Random rand = new Random();
            int numLetters = rand.Next(4, 13);  // 4-12 characters
            string name = "";
            for (int i = 1; i <= numLetters; i++)
                name = name + (char)('a' + rand.Next(0, 26));

            return name;
        }
    }

#1,207 – C# 6.0 – Auto-Property Initializers for Read-Only Properties

Prior to C# 6.0, if you wanted a read-only (immutable) property, you’d typically use a read-only backing field that is initialized in the constructor, as shown below.

    public class Dog 
    {
        public string Name { get; set; }

        // DogCreationTime is immutable
        private readonly DateTime creTime;
        public DateTime DogCreationTime 
        {
            get { return creTime; }
        }

        public Dog(string name)
        {
            Name = name;
            creTime = DateTime.Now;
        }
    }

In C# 6.0, you can use auto-implemented properties to implement a read-only property.  You do this by using an auto-property initializer.  The result is much cleaner than the above example, where we had to explicitly declare a backing field.

    public class Dog
    {
        public string Name { get; set; }

        // DogCreationTime is immutable
        public DateTime DogCreationTime { get; } = DateTime.Now;

        public Dog(string name)
        {
            Name = name;
        }
    }

#1,206 – C# 6.0 – Auto-Property Initializers

C# 3.0 introduced auto-implemented properties.

Older syntax:

private string name = "default";
public string Name
{
    get { return name; }
    set { name = value; }
}

Improved syntax, using auto-implemented properties:

public string Name { get; set; }

The new syntax provided no mechanism for specifying a default property value. To specify a default value, you either needed to go back to using an explicit backing variable or to set the default value from within a constructor.

C# 6.0 supports specifying default values for auto-implemented properties, as shown below.

        public string Name { get; set; } = "default";

#1,205 – C# 6.0 – Using the Null-Conditional when Invoking a Delegate

When you fire an event (by invoking a delegate), you typically need to check for null before invocation.  This avoids a null reference exception if there are no subscribers to the event.

    public class Dog
    {
        public Dog(string name, int age)
        {
            Name = name;
            Age = age;
        }

        public event EventHandler<string> NameChange;

        private string name;
        public string Name
        {
            get { return name; }
            set
            {
                if (value != name)
                {
                    name = value;

                    // Check for null before invocation
                    if (NameChange != null)
                    {
                        NameChange(this, name);
                    }
                }
            }
        }

        public int Age { get; set; }
    }

(The above pattern is not thread-safe).

An alternative pattern is to declare the event with a null handler, so that there is always at least one handler on the invocation list. (This is thread-safe).

In C# 6.0, we can use the null-conditional to invoke a delegate.

                    NameChange?.Invoke(this, name);

#1,204 – C# 6.0 – Using Null-Conditional with Indexer

The new null-conditional operator in C# 6.0 allows checking for null and de-referencing a variable in a single step.

You can use the null-conditional operator with dot (.) notation, to access an object’s properties or to invoke a method.  You can also use the null-conditional with an indexer, as shown below.  The expression returns the value returned by the indexer if the variable is non-null, or returns null if the variable is null.

            string sTest = "Howdy";

            char? thirdChar = sTest?[2];   // 'w'

            sTest = null;
            thirdChar = sTest?[2];   // null

            sTest = "Ho";
            thirdChar = sTest?[2];   // throws IndexOutOfRangeException

Notice that the null-conditional operator protects you from de-referencing a null pointer, but does not protect you from using an index that is longer than the string length.

#1,203 – C# 6.0 – Using the Null-Conditional with Value Types

The new null-conditional allows checking for null and de-referencing a reference-typed variable in a single step.

            string sLeft = sTest?.Substring(0, 1);

If the variable being checked for null (e.g. sTest) is null, the result of the expression is null.  This works as expected if the result of the expression is being assigned to a reference-typed variable (e.g. sLeft).  If the method or property being invoked, however, is a value type, then the result of the expression must be a nullable type.

For example, we might do the following in C# 5.0:

            int sLen;
            if (sTest != null)
                sLen = sTest.Length;

If sTest is null, the assignment isn’t done and sLen retains its value.

In C# 6.0, you can do this assignment using the null-conditional.  The variable being assigned to must be a nullable type whose base type matches the type of the expression.

            int? sLen = sTest?.Length;

#1,202 – C# 6.0 – Null-Conditional Operator

One of the new features coming in C# 6.0 is the null-conditional operator.

If you have a reference-typed variable, it can have a null value or can refer to instance of the appropriate type.  You’ll often see the following pattern, checking for null before invoking a method on the object, to avoid a NullReferenceException.

            string sTest = DateTime.Now.Hour == 5 ? "Five" : null;

            // OLD: Check for null to avoid NullReferenceException
            string sLeft;
            if (sTest != null)
                sLeft = sTest.Substring(0, 1);

The null-conditional operator allows us to do the same check for null, but in a more concise manner.

            // NEW: Null-Conditional operator
            sLeft = sTest?.Substring(0, 1);

If sTest is non-null, the Substring method is called and the result is assigned to sLeft.  If sTest is null, the expression returns null, so a null value is assigned to sLeft.

#1,201 – Writing Conditional Logical Operators as Conditionals

The conditional logical operators (&&, ||) can short-circuit evaluation, based on the value of the left side of the expression.

  • For &&, evaluation short-circuits if left-side is false (result is false)
  • For ||, evaluation short-circuits if left-side is true (result is true)

You can also think of the conditional logical operators as being equivalent to the ternary conditional operator.

            bool leftSide = true;
            bool rightSide = false;

            // Short-circuits (right side not evaluated)
            bool bResult = leftSide || rightSide;

            // || Equivalent to
            bResult = leftSide ? true : rightSide;

            // Short-circuits if left side is false
            bResult = leftSide && rightSide;

            // && Equivalent to
            bResult = leftSide ? rightSide : false;

#1,200 – Logical Operators vs. Conditional Logical Operators

You can use either the logical operators (|, &) or the conditional logical operators (||, &&) when comparing two boolean values (or expressions).

            bool isFromMN = true;
            bool likesConfrontation = false;

            bool bResult = likesConfrontation & isFromMN;  // false
            bResult = likesConfrontation && isFromMN;      // false
            bResult = likesConfrontation | isFromMN;       // true
            bResult = likesConfrontation || isFromMN;       // true

The difference between these operators, when used with boolean values, is that the conditional logical operators can short-circuit evaluation, avoiding evaluation of the right side of the expression if possible.

            int val = 0;

            // Short-circuits (right side not evaluated)
            bResult = isFromMN || ((5 / val) == 1);     // true 

            // Throws exception (does not short-circuit)
            bResult = isFromMN | ((5 / val) == 1);