Right Money Management App For Your Financial Goals
MVP Showcase 2015 - C#
1. Independent Experts – Real World AnswersIndependent Experts – Real World Answers
Microsoft MVP Showcase
22 Abril 2015
C#Paulo Morgado
.NET / C#
2. Independent Experts – Real World AnswersIndependent Experts – Real World Answers
Social Responsability
MicrosoftMVPShowcase
22Abril2015
“OS DOUTORES PALHAÇOS
LEVAM ALEGRIA ÀS CRIANÇAS
HOSPITALIZADAS EM PORTUGAL”
http://www.narizvermelho.pt/
12. Independent Experts – Real World AnswersIndependent Experts – Real World Answers
Foo(); var task = FooAsync();
From the method signature (how people call it)
void Foo()
{
for (int i=0; i<100; i++)
Math.Sin(i);
}
From the method implementation (what resources it uses)
async Task FooAsync()
{
await client.DownloadAsync();
}
13. Independent Experts – Real World AnswersIndependent Experts – Real World Answers
Is this true for your async methods?
15. Independent Experts – Real World AnswersIndependent Experts – Real World Answers
synchronous block the current thread
asynchronous without spawning new threads
16. Independent Experts – Real World AnswersIndependent Experts – Real World Answers
void Foo() { FooAsync().Wait(); } -- will deadlock!!!
30. Independent Experts – Real World AnswersIndependent Experts – Real World Answers
public class Customer
{
public string First { get; set; } = "Jane";
public string Last { get; set; } = "Doe";
}
31. Independent Experts – Real World AnswersIndependent Experts – Real World Answers
public class Customer
{
public string Name { get; };
public Customer(string first, string last)
{
Name = first + " " + last;
}
}
public class Customer
{
public string First { get } = "Jane";
public string Last { get; } = "Doe";
}
32. Independent Experts – Real World AnswersIndependent Experts – Real World Answers
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;
public void Print() => Console.WriteLine(First + " " + Last);
33. Independent Experts – Real World AnswersIndependent Experts – Real World Answers
public string Name => First + " " + Last;
public Customer this[long id] => store.LookupCustomer(id);
34. Independent Experts – Real World AnswersIndependent Experts – Real World Answers
using static System.Console;
using static System.Math;
using static System.DayOfWeek;
class Program
{
static void Main()
{
WriteLine(Sqrt(3 * 3 + 4 * 4));
WriteLine(Friday - Monday);
}
}
35. Independent Experts – Real World AnswersIndependent Experts – Real World Answers
using static System.Linq.Enumerable; // The type, not the namespace
class Program
{
static void Main()
{
var range = Range(5, 17); // Ok: not extension
var odd = Where(range, i => i % 2 == 1); // Error, not in scope
var even = range.Where(i => i % 2 == 0); // Ok
}
}
36. Independent Experts – Real World AnswersIndependent Experts – Real World Answers
int? length = customers?.Length; // null if customers is null
Customer first = customers?[0]; // null if customers is null
int length = customers?.Length ?? 0; // 0 if customers is null
int? first = customers?[0].Orders?.Count(); // can be chained
PropertyChanged?.Invoke(this, args); // delegate invokation
37. Independent Experts – Real World AnswersIndependent Experts – Real World Answers
var s = $"{p.Name} is {p.Age} year{{s}} old";
var s = $"{p.Name,20} is {p.Age:D3} year{{s}} old";
var s = $"{p.Name} is {p.Age} year{(p.Age == 1 ? "" : "s")} old";
38. Independent Experts – Real World AnswersIndependent Experts – Real World Answers
if (x == null) throw new ArgumentNullException(nameof(x));
WriteLine(nameof(person.Address.ZipCode)); // prints "ZipCode"
39. Independent Experts – Real World AnswersIndependent Experts – Real World Answers
var numbers = new Dictionary<int, string>
{
[7] = "seven",
[9] = "nine",
[13] = "thirteen"
};
40. Independent Experts – Real World AnswersIndependent Experts – Real World Answers
try { … }
catch (SqlException e) when (myfilter(e))
{
…
}
41. Independent Experts – Real World AnswersIndependent Experts – Real World Answers
Resource res = null;
try
{
res = await Resource.OpenAsync(…); // You could do this.
…
}
catch (ResourceException e)
{
await Resource.LogAsync(res, e); // Now you can do this …
}
finally
{
await res?.CloseAsync(); // … and this.
}
46. Independent Experts – Real World AnswersIndependent Experts – Real World Answers
CompilationUnit
ClassDeclaration
MethodDeclaration
class C
{
void M()
{
}
}// C
▫
ParameterList Block
var tree = CSharpSyntaxTree.ParseText("...");
47. Independent Experts – Real World AnswersIndependent Experts – Real World Answers
CompilationUnit
ClassDeclaration
class C { MethodDeclaration }
EOF
void M ParameterList Block
( ) { }
class C
{
void M()
{
}
}// C
▫
48. Independent Experts – Real World AnswersIndependent Experts – Real World Answers
class∙C
{
∙∙∙∙void∙M()
∙∙∙∙{
∙∙∙∙}
}// C
▫
CompilationUnit
ClassDeclaration
class C { MethodDeclaration }
EOF
void M ParameterList Block
( )
{ }
SP EOL EOL // C
SPx4 SP
EOL
EOL
EOLSPx4 EOL SPx4
50. Independent Experts – Real World AnswersIndependent Experts – Real World Answers
http://blogs.msdn.com/b/lucian/archive/2013/11/23/talk-mvp-summit-async-best-practices.aspx
http://channel9.msdn.com/Series/Three-Essential-Tips-for-Async/Three-Essential-Tips-For-Async-
Introduction
http://curah.microsoft.com/45553/asyncawait-general
http://curah.microsoft.com/44400/async-and-aspnet
51. Independent Experts – Real World AnswersIndependent Experts – Real World Answers
https://github.com/dotnet/roslyn/wiki/New-Language-Features-in-C%23-6
52. Independent Experts – Real World AnswersIndependent Experts – Real World Answers
https://github.com/roslyn
https://roslyn.codeplex.com/
https://github.com/code-cracker/
https://github.com/dotnetAnalyzers/
https://github.com/icsharpcode/NRefactory/tree/roslyn
53. Independent Experts – Real World AnswersIndependent Experts – Real World Answers
Communities
MicrosoftMVPShowcase
22Abril2015
54. Independent Experts – Real World AnswersIndependent Experts – Real World Answers
We <3 love our sponsors ! MicrosoftMVPShowcase
22Abril2015
* Let me put that more strongly
* For goodness' sake, stop using async void everywhere.
* (At first that was going to be the title of my talk)
* We've seen that async void is a "fire-and-forget" mechanism
* Meaning: the caller is *unable* to know when an async void has finished.
* And the caller is *unable* to catch exceptions from an async void method.
* Guidance is to use async void solely for top-level event handlers.
* Everywhere else in code, like SendData, async methods should return Task.
* There’s one other danger, about async void and lambdas, I’ll come to it in a moment.
* Basically the problem boils down to events.
* Building a complicated UI that responds to events.
* The developer had tried one approach, keeping the event handlers local.
* That led to a nightmare of nested lambdas.
* We tried another approach, figuring out the game's state machine, and how it responds to events.
* That ended up being too global. That is, things that should have been local ended up being part of the global state machine. What should have been local variables were promoted to class fields.
* The thing is, we have to figure out a way to tame events.
* Events have been with us for a long time, and they'll be with us for a long time to come.
* WPF, Silverlight, even in Windows8, they're still full of events.
* The challenge is how to tame them.
* I'm going to show how we can tame them by wrapping them up with tasks.
* So what we've seen here is a very general technique
to wrap up event-based things into Task-returning async methods
* We used it to make our interactive game easier to architect.
* And whenever we see our event-based code starts to feel like a state-machine,
that's a good time to think whether awaiting for events might be easier.
* And can turn so many things into awaitable Task w/ TaskCompletionSource
* Oh. Just hold on there a moment.
* What the heck kind of deserialization takes so long? 100ms per house? That's an eternity.
* Well, I checked with the developer.
* Turns out his deserialization wasn't really what I'd call deserialization.
* It was looking up tables in a database.
* That's why it took so long. It was network-bound, not CPU-bound.
* So let's review.
* It's vital to distinguish between what is CPU-bound work and what is IO-bound work.
* CPU-bound means things like LINQ-to-objects, or iterations, or computationally-intensive inner loops.
* Parallel.ForEach and Task.Run are good ways to put these CPU-bound workloads on the threadpool.
* But it's important to understand that threads haven't increased scalability
* Scalability is about not wasting resources
* One of those resources is threads
* Let's say your server can handle 1000 threads.
* If you had 1 thread per request, then you could handle 1000 requests at a time.
* But if you created 2 threads per request, then only 500 requests at a time.
* Oh. Just hold on there a moment.
* What the heck kind of deserialization takes so long? 100ms per house? That's an eternity.
* Well, I checked with the developer.
* Turns out his deserialization wasn't really what I'd call deserialization.
* It was looking up tables in a database.
* That's why it took so long. It was network-bound, not CPU-bound.
* There are two ways of thinking about asynchrony.
* First is from the method signature, the contract, how people will call it:
[CLICK]
* Synchronous signature means people expect to call it, to perform an operation here and now on this thread, and they won't get back control until it's done.
[CLICK]
* Asynchronous signature means people expect to call it to kick off an operation, but they'll get back control immediately to do whatever else they want.
[CLICK]
* Second way to look is from how it's actually implemented
[CLICK]
* An implementation that's synchronous is one that burns up a CPU core, doing work
[CLICK]
* An asynchronous implementation is one that's lighter, it barely touches the CPU, it just does small bits of work and schedules more.
* The thing is, your callers will look at your signature of your method, and they'll make assumptions right or wrong about how you're implemented underneath.
* It'll be your job to stay in line with those expectations.
* So what are the assumptions people will make?
* Imagine someone comes up to your API.
* They're going to read the documentation.
* Hah! Who am I kidding? They might read the XML doc-comments if we're lucky.
* They're going to say "Hey, here's a method, its name ends with Async, so..."
[CLICK]
* Maybe I'm in a server app. I bet this method's not going to spawn new threads.
* I can trust this method to be a good citizen on my server.
[CLICK]
* I also know that I can parallelize it.
* Maybe it's a download API. I can kick off 10 downloads simultaneously, just by invoking it 10 times and then awaiting Task.WhenAll.
* And it's not going to be hurting my scalability to do so.
[CLICK]
* These are the assumptions people make when they see "Async" at the end of your library method.
* What you have to ask yourselves is this: is it actually true for the async methods you're creating?
* We're going to look at an example where this isn't actually true.
[VS]
TreadPoolScaling.Run() // uncomment
Go To Definition
* There are going to be a number of small demos in this talk.
* This first one is about what happens when a library uses Task.Run internally.
* Simple app, console app, but I'm just spinning up a Winforms dialog here.
* This is the minimal code I need to get a UI message-loop. (don't want rest of plumbing)
class IO
* It's a demo of a library, so we'll have three layers: the app that uses the library then the library itself then the underlying framework functionality that the library uses.
* In this case, just as simulation, my OS provides two forms of its DownloadFile API
* One of them's truly synchronous - it really does tie up the thread. Doesn't burn the CPU, but does block the CPU.
* The other one's truly asynchronous - not using CPU, not tying up Thread.
class Library
* Here's one way to write the library. It wants to offer up an asynchronous API
* And in this version, it's using the synchronous OS API. Maybe that's the only one available.
* So to become async, my API needs to wrap it, with await Task.Run
* It's the top-right quadrant. It looks async, but it's wrapping an implementation that's synchronous.
* Probably to avoid blocking the callign thread.
b.Click += async delegate
* And here's what the app developer wrote, the user of my library.
* They want to be asynchronous, they want to stay responsive.
* But say they don't want just one, but they want to download 100 files.
* They saw that it was an async method, so they trusted they could just kick off all the tasks and then await Task.WhenAny
[RUN]
* Now it has kicked off all 100 of those tasks.
* But because each one wants to use a background thread, it's actually going in bursts.
* I have four logical cores on this laptop, so the threadpool starts by giving me four threads. As many threads as we have cores.
* Then it looks a second later, says it looks like you've made crappy use of those threads, most of them were idle, waiting on IO
* So it looks like you need more threads
[RUN]
* See the first batch was 4, then next batch was 5, then 6
* The threadpool has this predefined scaling behavior, hill-climbing
* So I've had to wait until the threadpool catches up to me, until it eventually finds its optimal number.
* But actually my app didn't need any threads.
* As an app author, I didn't even think any threads were involved.
* That's the key. You don't want to go messing with things that aren't yours, global resources.
* And the threadpool is one of those things.
* It belongs to the app developer, not to you the library author.
* They might have their own ideas about how they want to use the threadpool.
var contents = await IO.DownloadFileAsync()
* Now this one's pure async
[RUN]
* And this time all 100 files can download at the same time.
* This is what we'd expect.
* I shouldn't have to block waiting for the threadpool to grow
* I just have the assumption that I'm just kicking off work from the UI thread.
* You don't want to be a library author who violates that assumption
[CLICK]
* If your library's using Task.Run, you're putting in roadblocks that prevent the app from using its threads effectively
* If they want to go put some synchronous thing on a background thread, let them do that themselves.
* You should expose something that looks like what it is.
* If you only have an implementation that's synchronous, then expose as an API that's synchronous.
* Let them make that call about threading. It's not your call.
[CLICK]
* That's because the threadpool is that app-global resource.
[CLICK]
* In a server app, spinning up a bunch of threads hurts scalability.
* I don't want to create new threads, because my caller might be relying on those other threads to be request-threads, to handle new incoming requests.
* And imagine if my library uses Task.Run deep inside - then it'll be a pain for users to diagnose.
* It wasn't a mistake they made. It was a mistake for them to trust my API.
[CLICK]
* The app is in the best position to manage its threads.
* You should leave that to the app.
* Only provide async methods when you can implement them asynchronously.
* Let the user use their own domain-knowledge about what they're building to decide how they want to manage threads.
* Sometimes you think, "well I've implemented FooAsync(). shall I also implement Foo()? Not everybody's going to want to await."
* Why don't I just give them a helper, with the same implementation as FooAsync, but with a contract that's synchronous?
[CLICK]
* User's going to see that there are two versions of your API, one synchronous, one asynchronous.
* They'll assume the sync version must be faster than the async, otherwise why else would it be defined?
[CLICK]
* Also, suppose I'm the UI thread or complicated code where for whatever reason I don't want to await. Or suppose I'm on a constructor or one of those other places where I can't await. Maybe it'll be quick enough just to take 5-10ms to call the sync version from the UI thread, because my domain-specific knowledge knows it'll be okay.
[CLICK]
* That's what user will think when see that you have both sync and async.
* I wrote this sync version at the bottom. It's the wrong thing to do. It violates that assumption.
* Worse than that, it will actually DEADLOCK!
* That's because the call to Wait blocks the UI thread, and prevents any awaits from resuming.
* So, don't do it! Don't ever use .Wait() or .Result in a library method if you might be called on the UI thread.
* We're going to look at an example where this isn't actually true.
[VS]
TreadPoolScaling.Run() // uncomment
Go To Definition
* There are going to be a number of small demos in this talk.
* This first one is about what happens when a library uses Task.Run internally.
* Simple app, console app, but I'm just spinning up a Winforms dialog here.
* This is the minimal code I need to get a UI message-loop. (don't want rest of plumbing)
class IO
* It's a demo of a library, so we'll have three layers: the app that uses the library then the library itself then the underlying framework functionality that the library uses.
* In this case, just as simulation, my OS provides two forms of its DownloadFile API
* One of them's truly synchronous - it really does tie up the thread. Doesn't burn the CPU, but does block the CPU.
* The other one's truly asynchronous - not using CPU, not tying up Thread.
class Library
* Here's one way to write the library. It wants to offer up an asynchronous API
* And in this version, it's using the synchronous OS API. Maybe that's the only one available.
* So to become async, my API needs to wrap it, with await Task.Run
* It's the top-right quadrant. It looks async, but it's wrapping an implementation that's synchronous.
* Probably to avoid blocking the callign thread.
b.Click += async delegate
* And here's what the app developer wrote, the user of my library.
* They want to be asynchronous, they want to stay responsive.
* But say they don't want just one, but they want to download 100 files.
* They saw that it was an async method, so they trusted they could just kick off all the tasks and then await Task.WhenAny
[RUN]
* Now it has kicked off all 100 of those tasks.
* But because each one wants to use a background thread, it's actually going in bursts.
* I have four logical cores on this laptop, so the threadpool starts by giving me four threads. As many threads as we have cores.
* Then it looks a second later, says it looks like you've made crappy use of those threads, most of them were idle, waiting on IO
* So it looks like you need more threads
[RUN]
* See the first batch was 4, then next batch was 5, then 6
* The threadpool has this predefined scaling behavior, hill-climbing
* So I've had to wait until the threadpool catches up to me, until it eventually finds its optimal number.
* But actually my app didn't need any threads.
* As an app author, I didn't even think any threads were involved.
* That's the key. You don't want to go messing with things that aren't yours, global resources.
* And the threadpool is one of those things.
* It belongs to the app developer, not to you the library author.
* They might have their own ideas about how they want to use the threadpool.
var contents = await IO.DownloadFileAsync()
* Now this one's pure async
[RUN]
* And this time all 100 files can download at the same time.
* This is what we'd expect.
* I shouldn't have to block waiting for the threadpool to grow
* I just have the assumption that I'm just kicking off work from the UI thread.
* You don't want to be a library author who violates that assumption
[CLICK]
* If your library's using Task.Run, you're putting in roadblocks that prevent the app from using its threads effectively
* So let's review.
* It's vital to distinguish between what is CPU-bound work and what is IO-bound work.
* CPU-bound means things like LINQ-to-objects, or iterations, or computationally-intensive inner loops.
* Parallel.ForEach and Task.Run are good ways to put these CPU-bound workloads on the threadpool.
* But it's important to understand that threads haven't increased scalability
* Scalability is about not wasting resources
* One of those resources is threads
* Let's say your server can handle 1000 threads.
* If you had 1 thread per request, then you could handle 1000 requests at a time.
* But if you created 2 threads per request, then only 500 requests at a time.
* We're going to look at an example where this isn't actually true.
[VS]
TreadPoolScaling.Run() // uncomment
Go To Definition
* There are going to be a number of small demos in this talk.
* This first one is about what happens when a library uses Task.Run internally.
* Simple app, console app, but I'm just spinning up a Winforms dialog here.
* This is the minimal code I need to get a UI message-loop. (don't want rest of plumbing)
class IO
* It's a demo of a library, so we'll have three layers: the app that uses the library then the library itself then the underlying framework functionality that the library uses.
* In this case, just as simulation, my OS provides two forms of its DownloadFile API
* One of them's truly synchronous - it really does tie up the thread. Doesn't burn the CPU, but does block the CPU.
* The other one's truly asynchronous - not using CPU, not tying up Thread.
class Library
* Here's one way to write the library. It wants to offer up an asynchronous API
* And in this version, it's using the synchronous OS API. Maybe that's the only one available.
* So to become async, my API needs to wrap it, with await Task.Run
* It's the top-right quadrant. It looks async, but it's wrapping an implementation that's synchronous.
* Probably to avoid blocking the callign thread.
b.Click += async delegate
* And here's what the app developer wrote, the user of my library.
* They want to be asynchronous, they want to stay responsive.
* But say they don't want just one, but they want to download 100 files.
* They saw that it was an async method, so they trusted they could just kick off all the tasks and then await Task.WhenAny
[RUN]
* Now it has kicked off all 100 of those tasks.
* But because each one wants to use a background thread, it's actually going in bursts.
* I have four logical cores on this laptop, so the threadpool starts by giving me four threads. As many threads as we have cores.
* Then it looks a second later, says it looks like you've made crappy use of those threads, most of them were idle, waiting on IO
* So it looks like you need more threads
[RUN]
* See the first batch was 4, then next batch was 5, then 6
* The threadpool has this predefined scaling behavior, hill-climbing
* So I've had to wait until the threadpool catches up to me, until it eventually finds its optimal number.
* But actually my app didn't need any threads.
* As an app author, I didn't even think any threads were involved.
* That's the key. You don't want to go messing with things that aren't yours, global resources.
* And the threadpool is one of those things.
* It belongs to the app developer, not to you the library author.
* They might have their own ideas about how they want to use the threadpool.
var contents = await IO.DownloadFileAsync()
* Now this one's pure async
[RUN]
* And this time all 100 files can download at the same time.
* This is what we'd expect.
* I shouldn't have to block waiting for the threadpool to grow
* I just have the assumption that I'm just kicking off work from the UI thread.
* You don't want to be a library author who violates that assumption
[CLICK]
* If your library's using Task.Run, you're putting in roadblocks that prevent the app from using its threads effectively
* So let's review.
* It's vital to distinguish between what is CPU-bound work and what is IO-bound work.
* CPU-bound means things like LINQ-to-objects, or iterations, or computationally-intensive inner loops.
* Parallel.ForEach and Task.Run are good ways to put these CPU-bound workloads on the threadpool.
* But it's important to understand that threads haven't increased scalability
* Scalability is about not wasting resources
* One of those resources is threads
* Let's say your server can handle 1000 threads.
* If you had 1 thread per request, then you could handle 1000 requests at a time.
* But if you created 2 threads per request, then only 500 requests at a time.
* Another lesson for async library developers is to use ConfigureAwait(false).
* I need to get technical. Talk about "SynchronizationContext".
* It represents a target for work
* Has a core method called "Post"
* You invoke Post to get back into a particular context.
[CLICK]
* For example, in Winforms, if you get the current SynchronizationContext and do Post on it, it does a Control.BeginInvoke. That's how Winforms gets onto the UI thread.
[CLICK]
* And in WPF/Silverlight/Win8 it's similar, the DispatcherSynchronizatonContext. When you do a Post on it, it uses Dispatcher.BeginInvoke.
[CLICK]
* And ASP.Net current synchronization context, when you do Post() on it, it schedules work to be done in its own way.
* There are about 10 in the framework, and you can create more.
* And this is the core way that the await keyword knows how to put you back where you were.
* So when you do await, it first captures the current SyncContext before awaiting.
* When it resumes, it uses SyncContext.Post() to resume "in the same place" as it was before
[CLICK]
* For app code, this is the behavior that you almost always want.
* When you await a download, say, you want to come back and update the UI.
[CLICK]
* But when you're a library author, it's rarely the behavior that you want.
* You usually don't care which threading context you come back on, inside your library methods.
* It doesn't matter if your library method finishes off on a different thread either, maybe the IO completion port thread.
* That's because when the user awaited on your library method, then their own await is going to put them back where they wanted. They don't need to rely on you.
* And so in the framework we provide this helper method Task.ConfigureAwait.
* Use it on your await operator.
* Default, true, means the await should use SynchronizationContext.Post to resume back where it left off
* If you pass in false, then if possible it'll skip that and just continue where it is, maybe the IO completion-port thread
* Let's just stay there! is as good a place as any!
[CLICK]
* If your library doesn't do this, and you're using await in an inner loop, then you're waisting the user's message-loop
* being a bad citizen, flooding THEIR UI thread with messages that don't have anything to do with them
* Another lesson for async library developers is to use ConfigureAwait(false).
* Another lesson for async library developers is to use ConfigureAwait(false).
* We've talked about perf considerations.
* Async is as fast as it can be, and the inherent overheads are only noticeable in a tight inner loop. We're talking millions of iterations, not just a few hundred or thousand.
* If we can't help, and our API has to be called frequently, there are some great built-in perf features
* First, there was the "Fast Path". If an await has already completed, then it just plows right through it.
* And if you get to the end of the method without any "slow-path" awaits, then you avoid a bunch of memory allocations.
* Guidance is, try to avoid chatty APIs. Make APIs where the consumer of your library doesn't have to await in an inner loop.
* You can GetNextKilobyteAsync() instead of GetNextBitAsync().
* If you have to, we saw how to cache the returned Task<T> to remove the one last allocation on the fast path.
* Using your domain knowledge that YOU have about the nature of YOUR API can let YOU decide to cache tasks in a way that makes sense.
* Another lesson for async library developers is to use ConfigureAwait(false).
The initializer directly initializes the backing field; it doesn’t work through the setter of the auto-property. The initializers are executed in order as written, just as – and along with – field initializers.
Just like field initializers, auto-property initializers cannot reference this – after all they are executed before the object is properly initialized.
The backing field of a getter-only auto-property is implicitly declared as readonly (though this matters only for reflection purposes). It can be initialized through an initializer on the property as in the example above. Also, a getter-only property can be assigned to in the declaring type’s constructor body, which causes the value to be assigned directly to the underlying field:
This is about expressing types more concisely, but note that it also removes an important difference in the language between mutable and immutable types: auto-properties were a shorthand available only if you were willing to make your class mutable, and so the temptation to default to that was great. Now, with getter-only auto-properties, the playing field has been leveled between mutable and immutable.
Methods as well as user-defined operators and conversions can be given an expression body by use of the “lambda arrow”:
The effect is exactly the same as if the methods had had a block body with a single return statement.
For void-returning methods – and Task-returning async methods – the arrow syntax still applies, but the expression following the arrow must be a statement expression (just as is the rule for lambdas):
Properties and indexers can have getters and setters. Expression bodies can be used to write getter-only properties and indexers where the body of the getter is given by the expression body:
Note that there is no get keyword: It is implied by the use of the expression body syntax.
The feature allows all the accessible static members of a type to be imported, making them available without qualification in subsequent code:
This is great for when you have a set of functions related to a certain domain that you use all the time. System.Math would be a common example of that. It also lets you directly specify the individual named values of an enum type, like the System.DayOfWeek members above.
Extension methods are static methods, but are intended to be used as instance methods. Instead of bringing extension methods into the global scope, the using static feature makes the extension methods of the type available as extension methods:
This does mean that it can now be a breaking change to turn an ordinary static method into an extension method, which was not the case before. But extension methods are generally only called as static methods in the rare cases where there is an ambiguity. In those cases, it seems right to require full qualification of the method anyway.
String.Format and its cousins are very versatile and useful, but their use is a little clunky and error prone. Particularly unfortunate is the use of {0} etc. placeholders in the format string, which must line up with arguments supplied separately:
var s = String.Format("{0} is {1} year{{s}} old", p.Name, p.Age);
String interpolation lets you put the expressions right in their place, by having “holes” directly in the string literal:
var s = $"{p.Name} is {p.Age} year{{s}} old";
Just as with String.Format, optional alignment and format specifiers can be given:
var s = $"{p.Name,20} is {p.Age:D3} year{{s}} old";
The contents of the holes can be pretty much any expression, including even other strings:
var s = $"{p.Name} is {p.Age} year{(p.Age == 1 ? "" : "s")} old";
Notice that the conditional expression is parenthesized, so that the : "s" doesn’t get confused with a format specifier.
String.Format and its cousins are very versatile and useful, but their use is a little clunky and error prone. Particularly unfortunate is the use of {0} etc. placeholders in the format string, which must line up with arguments supplied separately:
var s = String.Format("{0} is {1} year{{s}} old", p.Name, p.Age);
String interpolation lets you put the expressions right in their place, by having “holes” directly in the string literal:
var s = $"{p.Name} is {p.Age} year{{s}} old";
Just as with String.Format, optional alignment and format specifiers can be given:
var s = $"{p.Name,20} is {p.Age:D3} year{{s}} old";
The contents of the holes can be pretty much any expression, including even other strings:
var s = $"{p.Name} is {p.Age} year{(p.Age == 1 ? "" : "s")} old";
Notice that the conditional expression is parenthesized, so that the : "s" doesn’t get confused with a format specifier.
Occasionally you need to provide a string that names some program element: when throwing an ArgumentNullException you want to name the guilty argument; when raising a PropertyChanged event you want to name the property that changed, etc.
Using string literals for this purpose is simple, but error prone. You may spell it wrong, or a refactoring may leave it stale. nameof expressions are essentially a fancy kind of string literal where the compiler checks that you have something of the given name, and Visual Studio knows what it refers to, so navigation and refactoring will work:
(if x == null) throw new ArgumentNullException(nameof(x));
You can put more elaborate dotted names in a nameof expression, but that’s just to tell the compiler where to look: only the final identifier will be used:
WriteLine(nameof(person.Address.ZipCode)); // prints "ZipCode"
Object and collection initializers are useful for declaratively initializing fields and properties of objects, or giving a collection an initial set of elements. Initializing dictionaries and other objects with indexers is less elegant. We are adding a new syntax to object initializers allowing you to set values to keys through any indexer that the new object has:
VB has them. F# has them. Now C# has them too. This is what they look like:
try { … } catch (MyException e) when (myfilter(e)) { … }
If the parenthesized expression evaluates to true, the catch block is run, otherwise the exception keeps going.
Exception filters are preferable to catching and rethrowing because they leave the stack unharmed. If the exception later causes the stack to be dumped, you can see where it originally came from, rather than just the last place it was rethrown.
It is also a common and accepted form of “abuse” to use exception filters for side effects; e.g. logging. They can inspect an exception “flying by” without intercepting its course. In those cases, the filter will often be a call to a false-returning helper function which executes the side effects:
private static bool Log(Exception e) { /* log it */ ; return false; } … try { … } catch (Exception e) when (Log(e)) {}
In C# 5 we don’t allow the await keyword in catch and finally blocks, because we’d somehow convinced ourselves that it wasn’t possible to implement. Now we’ve figured it out, so apparently it wasn’t impossible after all.
This has actually been a significant limitation, and people have had to employ unsightly workarounds to compensate. That is no longer necessary:
* Another lesson for async library developers is to use ConfigureAwait(false).
* Another lesson for async library developers is to use ConfigureAwait(false).