Expression-bodied methods

The next release of C# 6 has some amazing new features. In a series of blog posts I will cover some of them.

Expression-bodied methods make it possible for methods and properties to be used as expressions instead of statement blocks, just like lambda functions.

Let’s revisit the Person.ToString method in the Awesome string formatting blog post.

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

  public Address HomeAddress { get; set; }

  public override string ToString()
  {
    return string.Format("{Name} lives in {HomeAddress?.City ?? "City unknown"}.");
  }
}

The ToString method can be written as a lambda function.

public override string ToString() => string.Format("{Name} lives in {HomeAddress?.City ?? "City unknown"}.");

And simplified with String interpolation.

public override string ToString() => $"{Name} lives in {HomeAddress?.City ?? "City unknown"}.

Use expression-bodied methods anywhere…

public Point Move(int dx, int dy) => new Point(x + dx, y + dy);
public static Complex operator +(Complex a, Complex b) => a.Add(b);
public static implicit operator string (Person p) => "\{p.First} \{p.Last}";

Awesome string formatting

The next release of C# 6 has some amazing new features. In a series of blog posts I will cover some of them.

Using the versatile string.Format required a lot of typing and keeping the numbed placeholders in sync with the method parameters.

var numerator = 1;
var denominator = 2;

Console.WriteLine("Fraction {0}/{1}", numerator, denominator);

// Output:
//   Fraction 1/2

In C# 6 is it a lot easier with String interpolation:

var numerator = 1;
var denominator = 2;

Console.WriteLine("Fraction {numerator}/{denominator}");

// Output:
//   Fraction 1/2

Referencing the variable, property or field directly within the string. It is even possible to access properties or use expressions.

public class Person
{
  public string Name { get; set; }
  public Address HomeAddress { get; set; }

  public override string ToString()
  {
    return string.Format("{Name} lives in {HomeAddress.City}.");
  }
}

The string.Format is not event needed, but use the shorthand notation $.

return $("{Name} lives in {HomeAddress.City}.";

This is easily combinable with an expression and the null-conditional operator (?.) operator.

return $"{Name} lives in {HomeAddress?.City ?? "City unknown"}.";

The nameof operator

The next release of C# 6 has some amazing new features. In a series of blog posts I will cover some of them.

The nameof operator takes a class, method, property, field or variable and returns the string literal.

var p = new Person();

Console.WriteLine(nameof(Person));
Console.WriteLine(nameof(p));
Console.WriteLine(nameof(Person.Name));
Console.WriteLine(nameof(Person.HomeAddress));

// Output:
//   Person
//   p
//   Name
//   HomeAddress

This is handy when doing input validation by keeping the method parameter and the parameter name of the ArgumentNullException in sync.

public Point AddPoint(Point point)
{
  if (point == null)
    throw new ArgumentNullException(nameof(point));
}

The nameof operator is useful when implementing the INotifyPropertyChanged interface

public string Name
{
  get
  {
    return _name;
  }
  set
  {
    _name = value;
    this.OnPropertyChanged(nameof(Name));
  }
}

The Chained null checks blog post shows how to simplify triggering event in the OnPropertyChanged with the null-conditional operator.

Chained null checks

The next release of C# 6 has some amazing new features. In a series of blog posts I will cover some of them.

Null-conditional operators is one of the features in C# 6 that will save the world from a lot of boilerplate code and a bunch of NullReferenceExceptions. It works as chained null checks!

Console.WriteLine(person?.HomeAddress?.City ?? "City unknown");

Note the null-conditional operator (?.) after person and HomeAddress, it returns null and terminates the object reference chain, if one of the references are null.

It is the same logic as the below code that you can use today.

if (person != null)
    person.HomeAddress != null)
{
  Console.WriteLine(person.HomeAddress.City);
}
else
{
  Console.WriteLine("City unknown");
}

The null-conditional operator will also make it easier to trigger events. Today it is required to reference the event, check if it is null before raising the event like so.

protected void OnPropertyChanged(string name)
{
  PropertyChangedEventHandler handler = PropertyChanged;

  if (handler != null)
  {
    handler(this, new PropertyChangedEventArgs(name));
  }
}

But the null-conditional operator provides a tread-safe way of checking for null before triggering the event.

PropertyChanged?.Invoke(this, args);

AJAX paging for ASP.NET MVC sites

When working with lists of data paging is a necessity, but trivial to implement in an ASP.NET MVC. The article Sorting, Filtering, and Paging with the Entity Framework in an ASP.NET MVC Application on www.asp.net makes use of the PackedList.MVC NuGet package and each step is described in detail. The implementation requires full-page refresh and does not make use of AJAX capabilities.

Let us extend the implementation and make full use of the AJAX capabilities.

Wrap the entire table in a div-tag and give it an id of content – it will enable us to replace the table without refreshing the entire webpage.

<div id="content">
    <table>
        ... removed for brevity
    </table>

    <div id="contentPager">
        @Html.PagedListPager(Model, page => Url.Action("Index", new { page }))
    </div>
</div>

Also wrap the @Html.PagedListPager in a div-tag and set the id to contentPager – it will let us alter the behavior of the click-event.

The below JQuery code attaches the anonymous function to every a-tag within the contentPager element and the function replaces the html within the content element with whatever is returned from the AJAX call.

$(document).on("click", "#contentPager a", function () {
    $.ajax({
        url: $(this).attr("href"),
        type: 'GET',
        cache: false,
        success: function (result) {
            $('#content').html(result);
        }
    });
    return false;
});

Move everything within the content element to a new view – let us call the new view List.

@model PagedList.IPagedList<ContosoUniversity.Models.Student>
@using PagedList.Mvc;

<div id="content">
    <table class="table">
      ... removed for brevity
    </table>

    <div id="contentPager">
        @Html.PagedListPager(Model, page => Url.Action("List", new { page }))
    </div>
</div>

Notice in above highlighted code, that the Action URL is changed to List, which is the name of the Action we need to add to the StudentController.

public ActionResult List(int? page)
{
    var students = from s in db.Students
                    orderby s.LastName
                    select s;

    int pageSize = 3;
    int pageNumber = (page ?? 1);
    return View(students.ToPagedList(pageNumber, pageSize));
}

The functionality of the new List Action is the same as in the existing Index Action. Just move all the code from the Index Action, so it just returns the default view as below.

public ViewResult Index()
{
    return View();
}

To wrap it up, the Index view needs to call the List Action to render the table in the Index view.

So the Index view ends up looking like this.

<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />
@{
    ViewBag.Title = "Students";
}
<h2>Students</h2>

@Html.Action("List")

@section scripts
{
    <script language="javascript" type="text/javascript">
        $(document).ready(function () {
            $(document).on("click", "#contentPager a[href]", function () {
                $.ajax({
                    url: $(this).attr("href"),
                    type: 'GET',
                    cache: false,
                    success: function (result) {
                        $('#content').html(result);
                    }
                });
                return false;
            });
        });
    </script>
}

That is it.

The solution is inspired by this StackOverflow question.

Download the complete solution, build and open the Student page.