I am experienced in Java, but recently I have been programming in C# and I found some cool features that I fell in love with. Lets take a look at some amazing stuff you can do with C#, but not in Java.
1. Async/await
There is no way for me to quickly explain C# async/await in a few sentences, but I will try nonetheless.
Basically it gives you a way to write asynchronous code using dedicated language constructs of Task
, async
and await
.
Each time you await
on a Task
, you declare that you need a result of asynchronous code(Task
) before the rest of the method can be executed. To use await
inside a method it needs to be marked as async async
public async Task SomeMethod()
{
var networkCall = _httpClient.GetAsync("https://google.com"); // returns Task, may or may not create and run annother thread in the background
var dbConnectionTask = GetDbHandleAsync(); // returns Task, may or may not create and run annother thread in the background
var networkResult = await networkCall; // this DOES NOT block the current thread, instead it can release it to the thread pool
var dbConnection = await dbConnectionTask();
dbConnection.DoSomethingWith(networkResult);
}
2. Top-level statements
We all know that you need to write public static void main(String[] args)
each time you want your Java program to run
class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
In C# it used to work the same way:
using System;
namespace Application
{
class HelloWorld
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}
But with C# 9.0 Top-level statements we don’t need that crap anymore :)
Console.WriteLine("Hello, World!");
I guess that is self-explanatory. Behind the scenes, the “old” code will be generated.
One gotcha in case of ASP.NET Core is integration testing.
3. Generics/reflection
In Java, generics are imlemented with type erasure, which means at runtime information abount generic type argument does not exist. Instead types are represented as Object
, and converted to/from actual type when needed. Not only is it slow, but also does not allow us to write reflection code around generics.
In C# generics are implemented all they way down to CLR. This means we can inspect the generic type at runtime:
var dict = new Dictionary<string, int>();
Type t = dict.GetType();
Type[] typeParameters = t.GetGenericArguments();
foreach( Type tParam in typeParameters )
{
Console.WriteLine("Type argument: {0}", tParam);
}
// prints
// Type argument: System.String
// Type argument: System.Int32
4. Nullable reference types
Remember Optional
? It is nice way to wrap value that may be null
.
In C# there is something similar: Nullable
.
But since C#8 has something even better. In short: you can use question mark to mark a type that allows null
. Otherwise type is assumed to always be not-null. You can use null-forgiving operator to change nullable type, to non-nullable one.
The biggest reason I like it is readability. You can clearly state your intentions with regards to nullablility of any variable or property.
private int GetLength(string? value)
{
// we can enable static analysis to warn or error if we don't check for null!
if (value == null)
{
return 0;
}
return value.Length;
}
5. String interpolation
Take a look how easy it is to do in C#:
var language = "Java";
var currentYear = DateTime.Now.Year;
Console.WriteLine($"It is {currentYear} and {language} still does not support string interpolation");
Overall Java is great language to program in. It has amazing community with a lot of great frameworks like spring. But if you want a change, try C#! It is really awesome and has some adventages over Java, while being really similar - you will quickly feel at home.