skype: pavel.nasovich
email: forcewake@gmail.com
| 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 | 
| 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! | 
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;
}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),
    };
}
    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);
}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()
    };
}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()
    };
}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;
    }
}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()
    {
    }
}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);
}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));
}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}";
}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;
}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
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();
    }
}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);
    }
}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);
    }
}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.
Codename "Roslyn"
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
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).
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);
}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;
    }
}