Refresher for new
.NET / C#
development techniques
Pavel Nasovich
skype: pavel.nasovich
email: forcewake@gmail.com
.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,077