Refresher for new

.NET / C#

development techniques

Pavel Nasovich

.Net Framework

history

Overview of Past Versions

C# Version Major Feature
C# 2.0 Generics
C# 3.0 LINQ, Expression Trees
C# 4.0 Dynamics,
Named/Optional Parameters, TPL
C# 5.0 Async/Await

Overview of Past Versions

C# Version Major Feature
C# 2.0 Generics
C# 3.0 LINQ
C# 4.0 Dynamics,
Named/Optional Parameters
C# 5.0 Async/Await
C# 6.0 Minor syntactic sugar!

C# 6.0

features

Async/Await in catch()/finally()

public async Task<string> ToTheInternet(string url)
{
    string result = "";

    try
    {
        HttpClient client = new HttpClient();
        result = await client.GetStringAsync(url);
    }
    catch (Exception ex)
    {
        await LogToRemoteService(ex.Message);
    }

    return result;
}

Using static statements

Before

After

public Vector2D RotateVector(Vector2D v, double angle)
{
    return new Vector2D()
    {
        X = v.X * Math.Cos(angle) - v.Y * Math.Sin(angle),
        Y = v.X * Math.Sin(angle) + v.Y * Math.Cos(angle),
    };
}
using System.Math;

public Vector2D RotateVector(Vector2D v, double angle)
{
    return new Vector2D()
    {
        X = v.X * Cos(angle) - v.Y * Sin(angle),
        Y = v.X * Sin(angle) + v.Y * Cos(angle),
    };
}

nameof() operator

Before

After

public void EatSandwich(Sandwich sandwich)
{
    if(sandwich == null)
    {
        throw new ArgumentNullException("sandwich");
    }

    Digest(sandwich);
}
public void EatSandwich(Sandwich sandwich)
{
    if (sandwich == null)
    {
        throw new ArgumentNullException(nameof(sandwich));
    }

    Digest(sandwich);
}

Indexer initializers

Before

After

public void InitCats()
{
    this.Cats = new Dictionary<string, Cat>()
    {
        { "PianoCat", new PianoCat()},
        { "CeilingCat", new CeilingCat()},
        { "MonorailCat", new MonorailCat()},
        { "LongCat", new LongCat()}
    };
}
public void InitCats()
{
    this.Cats = new Dictionary<string, Cat>()
    {
        ["PianoCat"] = new PianoCat(),
        ["CeilingCat"] = new CeilingCat(),
        ["MonorailCat"] = new MonorailCat(),
        ["LongCat"] = new LongCat()
    };
}

Indexer initializers - Differences

  • The { ____, ____ } syntax calls the Add()* method under the hood
  • The [ ____ ] = _____ syntax calls the []-indexer under the hood

Indexer initializers - Caveat

This results in a run-time ArgumentException

This results in a Dictionary with one key-value pair

public void InitCats()
{
    this.Cats = new Dictionary<string, Cat>()
    {
        { "LongCat", new LongCat()}
        { "LongCat", new TacGnol()}
    };
}
public void InitCats()
{
    this.Cats = new Dictionary<string, Cat>()
    {
        ["LongCat"] = new LongCat(),
        ["LongCat"] = new TacGnol()
    };
}

Getter-only auto-properties

Before

After

public class CannedPeachFactory
{
    public int NumPeaches { get; private set; }

    private int numPeachesForMe;
    public int NumPeachesForMe { get { return numPeachesForMe; } }

    public CannedPeachFactory()
    {
        NumPeaches = 3;
        numPeachesForMe = 300000000;
    }
}
public class CannedPeachFactory
{
    public int NumPeachesForMe { get; }

    public CannedPeachFactory()
    {
        NumPeachesForMe = 300000000;
    }
}

Initializers for auto-properties

Before

After

public class CannedPeachFactory
{
    public int NumPeaches { get; set; }

    public CannedPeachFactory()
    {
        NumPeaches = 300000000;
    }
}
public class CannedPeachFactory
{
    public int NumPeaches { get; set; } = 300000000;

    public CannedPeachFactory()
    {
    }
}

Expression-bodied properties

Before

After

public class lolcat
{
    public List<FoodItem> Food { get; } = new List<FoodItem>();

    public bool HasCheezburger
    {
        get
        {
            return Food.Any(x => x is Cheezburger);
        }
    }
}
public class lolcat
{
    public List<FoodItem> Food { get; } = new List<FoodItem>();

    public bool HasCheezburger => Food.Any(x => x is Cheezburger);
}

Expression-bodied methods

Before

After

public class Me
{
    public List<Pokeman> Pokemans { get; } = new List<Pokeman>();

    public void Show()
    {
        Console.WriteLine(String.Join(", ", Pokemans));
    }
}
public class Me
{
    public List<Pokeman> Pokemans { get; } = new List<Pokeman>();

    public void Show() => Console.WriteLine(String.Join(", ", Pokemans));
}

String interpolation

Before

After

public string FillIn(string verb, string adjective1, string adjective2)
{
    return String.Format("I {0} Mad Libs because they are {1} and {2}",
                         verb,
                         adjective1,
                         adjective2);
}
public string FillIn(string verb, string adjective1, string adjective2)
{
    return $"I {verb} Mad Libs because they are {adjective1} and {adjective2}";
}

Null-conditional operators

Before

After

public int GetNumOwnedBases(Organization org, BaseOwner owner)
{
    int ownedBases = 0;

    if (org != null && org.Bases != null)
    {
        ownedBases = org.Bases.Count(b => b.Owner == owner);
    }

    return ownedBases;
}
public int GetNumOwnedBases(Organization org, BaseOwner owner)
{
    int? ownedBases = org?.Bases?.Count(b => b.Owner == owner);

    return ownedBases ?? 0;
}

Null-conditional operators

After - Even more succinct

public int GetNumOwnedBases(Organization org, BaseOwner owner)
{
    return org?.Bases?.Count(b => b.Owner == owner) ?? 0;
}
public int GetNumOwnedBases(Organization org, BaseOwner owner)
{
    int? ownedBases = org?.Bases?.Count(b => b.Owner == owner);

    return ownedBases ?? 0;
}

After

Null-conditional operators - Indexers

Also works with indexers

public void MoveZIG(Armada armada)
{
    int bound = armada?.ZIGs?.Count ?? 0;

    for (int i = 0; i < bound; i++)
    {
        armada?.ZIGs?[i]?.Move();
    }
}

Null-conditional operators - Events

Before

After - Ideal scenario

public class ZIG
{
    public event EventHandler MainScreenTurnOn;

    public void OnMainScreenTurnOn()
    {
        EventHandler localCopy = MainScreenTurnOn;

        if (localCopy != null)
        {
            localCopy(this, EventArgs.Empty);
        }
    }
}
public class ZIG
{
    public event EventHandler MainScreenTurnOn;

    public void OnMainScreenTurnOn()
    {
        MainScreenTurnOn?(this, EventArgs.Empty);
    }
}

Null-conditional operators - Events

Ideal scenario is not allowed - DelegateName?() is illegal

public class ZIG
{
    public event EventHandler MainScreenTurnOn;

    public void OnMainScreenTurnOn()
    {
        MainScreenTurnOn?(this, EventArgs.Empty);
    }
}

Legal - DelegateName?.Invoke()

public class ZIG
{
    public event EventHandler MainScreenTurnOn;

    public void OnMainScreenTurnOn()
    {
        MainScreenTurnOn?.Invoke(this, EventArgs.Empty);
    }
}

Improved overload resolution

  • Multiple minor adjustments
  • The compiler should now do a better job of deciding which overload is more appropriate to use given some arguments
  • Things should work more often as you would expect them to.

What lies beyond

C# 6.0?

Features being considered for C# 7.0

  • Pattern matching
  • Tuples (as language built-ins)
  • Record types
  • Extension members
  • Collection slicing
  • Immutability
  • Async sequences
  • Method contracts
  • And more!

Why C# 6.0

is so poor?

.NET Core

  • Modular implementation of the .NET Framework

  • Open source

  • Designed for agile deployment over NuGet

  • Designed to be the a la carte base stack for different environments (desktop, phone, web, etc.)

  • Does not yet fully cover all the APIs spanned by .NET Framework; this set will get smaller over time.

.NET Compiler Platform

  • Open-sourced C# and VB.NET compiler
  • Provides code analysis API
  • Can be embedded into applications to serve as interpreter for scripts written in C#/VB.NET
  • Can be used for code generation
  • Can be used to build code analysis and diagnostics plug-ins for Visual Studio 2015

Codename "Roslyn"

.NET Core

features

.NET Core and ASP.NET CORE

​dotnet new
dotnet restore
dotnet run

May 2014

ASP.NET vNext announced

February 2015

ASP.NET 5 announced

November 2015

ASP.NET 5 and .NET Core RC 1

January 2016

ASP.NET Core and .NET Core RC 2

June 2016

ASP.NET Core and .NET Core 1.0

dnvm
dnx
dnu

Web Architecture

overview

Overview

A Web service, in very broad terms, is a method of communication between two applications or electronic devices over the World Wide Web (WWW).

Web services are of two kinds: Simple Object Access Protocol (SOAP) and Representational State Transfer (REST).

Warning

  • REST vs SOAP is not the right question to ask.
  • REST, unlike SOAP is not a protocol.
  • REST is an architectural style and a design for network-based software architectures.
  • REST concepts are referred to as resources. A representation of a resource must be stateless. It is represented via some media type. Some examples of media types include XML, JSON, and RDF. Resources are manipulated by components. Components request and manipulate resources via a standard uniform interface. In the case of HTTP, this interface consists of standard HTTP ops e.g. GET, PUT, POST, DELETE.

Evolution

Evolution

Microservices vs Monolithic

Pros

  • Deployability
  • Reliability
  • Availability
  • Scalability
  • Modifiability
  • Management
  • Design autonomy

Cons

  • Deployability
  • Performance
  • Availability
  • Modifiability
  • Testability
  • Management
  • Memory use
  • Runtime autonomy

Microservices vs Monolithic

System Architecture

overview

Repository evolution

public interface ICustomeRepository
{
    Customer GetCustomerById(Guid id);
    IEnumerable<Customer> SearchCustomersByName(string name);
    IEnumerable<Customer> SearchCustomersByNameAndRegion(string name, Region region);
    IEnumerable<Customer> GetActiveCustomers();
    IEnumerable<Customer> GetCustomersByPricingLevel(PricingLevel pricingLevel);
    IEnumerable<Customer> GetCustomersByPricingLevel(PricingLevel pricingLevel, bool active);
    IEnumerable<Customer> GetCustomersByRegion(Region region);
    IEnumerable<Customer> GetCustomersByRegion(Region region, bool active);

    IEnumerable<Customer> GetCustomersByRegionAndPricingLevel(
        Region region, 
        PricingLevel pricingLevel);

    IEnumerable<Customer> GetCustomersByRegionAndPricingLevel(
        Region region, 
        PricingLevel pricingLevel, 
        bool active);
}

Repository evolution

public class ChangeCustomerPricingLevel : IAsyncRequest
{
    public Guid CustomerId { get; }
    public PricingLevel PricingLevel { get; }

    public ChangeCustomerPricingLevel(Guid customerId, PricingLevel pricingLevel)
    {
        CustomerId = customerId;
        PricingLevel = pricingLevel;
    }
}

Commands & Queries

public class ChangePricingLevelHandler : IAsyncRequestHandler<ChangeCustomerPricingLevel, Unit>
{
    private CustomerContext _db;

    public ChangePricingLevelHandler(CustomerContext db)
    {
        _db = db;
    }

    public async Task<Unit> Handle(ChangeCustomerPricingLevel message)
    {
        var customer = _db.Customers.Single(x => x.CustomerId == message.CustomerId);
        customer.PrivingLevel = message.PricingLevel;
        await _db.SaveChangesAsync();

        return Unit.Value;
    }
}

Refresher for new .NET / C# development techniques

By Pavel Nasovich

Refresher for new .NET / C# development techniques

Let's try to refresh our knowledge about the .NET world and take a look to the modern .NET stuff.

  • 1,014