Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

C# 7.0: Throw Expressions

DZone's Guide to

C# 7.0: Throw Expressions

With C# 7.0, you can now throw exceptions in various parts of your code. Read on for details, including how to use them and a quick look at a compiled throw expression.

· Web Dev Zone ·
Free Resource

Deploy code to production now. Release to users when ready. Learn how to separate code deployment from user-facing feature releases with LaunchDarkly.

C# 7.0 introduces throw expressions. We can add exception throwing to expression-bodied members, null-coalescing expressions, and conditional expressions. This blog post introduces throw expressions, demonstrates how to use them, and also provides a peek behind a compiled throw expression.

Throw expressions are the way to tell the compiler to throw an exception under specific conditions like in expression bodied members or inline comparisons. Before going to some practical use cases let’s see some illustrative examples of throw expressions that were originally posted in the .NET Blog post, What’s New in C# 7.0.

class Person
{
    public string Name { get; }
    public Person(string name) => Name = name ?? throw new ArgumentNullException(name);
    public string GetFirstName()
    {
        var parts = Name.Split(' ');
        return (parts.Length > 0) ? parts[0] : throw new InvalidOperationException("No name!");
    }
    public string GetLastName() => throw new NotImplementedException();
}

Now let’s see what we can do with throw expressions in practice.

Throw Expressions in Unit Testing

We can use throw expressions when writing non-functioning methods and properties we plan to cover with tests. As these members usually throw NotImplementedException we can save some space here.

public class Customer
{
    // ...

    public string FullName => throw new NotImplementedException();public Order GetLatestOrder() => throw new NotImplementedException();
    public void ConfirmOrder(Order o) => throw new NotImplementedException();
    public void DeactivateAccount() => throw new NotImplementedException();
}

Of course, this example also has its dark side. It hides the fact that the class can grow too big and there can be a need to split it into smaller pieces.

Keeping Setters Short

Using throw expressions we can keep some setters short. Here is the FirstName property of Person class.

private string _firstName;

public string FirstName
{
    get => _firstName;
    set => _firstName = value ?? throw new ArgumentNullException();
}

Notice that throw expressions also work with null-coalescing operator (??).

Note: This example is not an example of best practices. It applies to properties that actually need body with some logic. If automatic properties and validation rules match your needs then go with these. Don’t change your code to use throw expressions just because they are here or they look cool.

Throw Expressions in Action

Here is the code example where some method arguments are compared to null.

public Order AddProductToNewOrder(Product product, Customer customer, double amount)
{
    if(product == null)
    {
        throw new ArgumentNullException(nameof(product));
    }if(customer == null)
    {
        throw new ArgumentNullException(nameof(customer));
    }       var orderLine = new OrderLine();
    orderLine.Product = product;
    orderLine.Amount = amount;var order = new Order();
    order.Customer = customer;
    order.AddLine(orderLine);                   return order;
}

We can make this code shorter by using throw expressions. Actually, Visual Studio proposes this change for us:

Visual Studio: simplify with throw expression

Here is the code with null check simplifications and some well-hidden land mines:

public Order AddProductToNewOrder(Product product, Customer customer, double amount)
{
    var orderLine = new OrderLine();
    orderLine.Product = product ?? throw new ArgumentNullException(nameof(product));
    orderLine.Amount = amount;var order = new Order();
    order.Customer = customer ?? throw new ArgumentNullException(nameof(customer));
    order.AddLine(orderLine);                   return order;
}

As far as creating order and order lines, creating new instances of simple classes are safe to go with this code. I don’t like the fact that objects are created. If new instances of order and order lines are created using factory classes we cannot use the code above as creating these instances may be a resource consuming or complex activity. Factory classes are usually not introduced for fun.

Behind the Compiler

Let’s take now the FirstName property shown above and see what the compiler produces from it. Without any guidance by PDB-file JetBrains dotPeek decompiles the property for us this way.

private string _firstName;

public string FirstName
{
    get
    {
        return this._firstName;
    }
    set
    {
        string str = value;
        if (str == null)
            throw new ArgumentNullException();
        this._firstName = str;
    }
}

As you can see, the throw expression is just a nice addition to the language and it doesn’t have any meaning at the runtime level. Without the PDB-file telling the decompiler the truth about the code in the library, we get back what was compiled.

Wrapping Up

Throw expressions are here to help us write smaller code and use exceptions in expression-bodied members. It is just a language feature and not anything fundamental in language runtime. Although throw expressions help us to write shorter code it is not a silver bullet or cure for every disease. Use throw expressions only when they can help you.

See also

Deploy code to production now. Release to users when ready. Learn how to separate code deployment from user-facing feature releases with LaunchDarkly.

Topics:
c# ,expressions ,web dev ,unit testing

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}