Posts

Showing posts with the label c#

What's in a Task?

Introduction Tasks in .NET have become ubiquitous: by now we all know that in order to make our apps and services more scalable (not necessarily performant, they are different concepts), we need to use them. A task is an operation that is designed to run in the background and which may or may not return a value. Tasks allow complex operations (I/O or CPU-bound) to be executed without blocking the main thread and are implemented by the Task  and  Task<T>  classes. These are actually monads  in mathematical and functional terminology, which means they have certain properties which I won't cover here. There are two ways by which we can call a method that is meant to be processed by another thread (one that returns  Task  or Task<T> , which inherits from  Task  but wraps a result): We use  await  to ask for the callee to be called by another thread and wait for its completion We omit  await  and have the callee processi...

C#/.NET Index

These are the posts in the series: Less Known LINQ Methods C# Records Implementing the Strategy Pattern with .NET Dependency Injection .NET 10 Validation Nullable and Required Types Working with Strings in .NET C# Magical Syntax .NET Collections .NET Metrics .NET Cancellation Tokens Service Discovery in .NET Retrieving Services from Dependency Injection in .NET The Evolution of .NET Dependency Resolution Named HttpClient Registrations What's in a Task?

Java Versus C# Index

These are the posts in the series: Java vs C# - Part 1 Java vs C# - Part 2 Java vs C# - Part 3 Java vs C# - Part 4 (TBD)

C# Records

Introduction C# records and record structs  are relatively new. Records offer some advantages over regular classes and structs, which I will cover here, but they are essentially another way to declare them. This is another back to basics article. We essentially use records for: Entities, such as the ones we would store in a database Value objects/ Data Transfer Objects Immutable classes Let's now see how to work with them. Syntax Records are declared like this: public record Point(int X, int Y); Or like this, with the exact same meaning: public record Point { public int X { get; init; } public int Y { get; init; } } And we instantiate a record just like any other class or struct: Point p1 = new(1, 2); //or var p1 = new Point(1, 2); We can, of course, use  positional or named arguments : var p1 = new Point(Y: 2, X: 1); It is possible to add new properties (or methods) besides the ones declared on the primary constructor , we don't need to live with just those pro...

Nullable and Required Types

Introduction Since the introduction of nullable reference types in C#, and also with the required keyword, I sometimes see some confusion, which I'm going to address here. This is kind of back to basics, but, yet, here we are! ;-) Reference Types A reference type in C#/.NET is a type that: Are instantiated on the heap Are passed by reference (pointer) Can be null Are declared with the class keyword (can also be record , in latest versions) Meaning, for example, that we can have this (string is a reference type): string str = null; str = "Hello, referece types!"; Value Types On the other hand, value types : Are instantiated on the stack Are passed by value (copied on every method call) Cannot be null Always have a value Are declared using the struct , enum , or record struct keywords Implicitly inherit from System.ValueType Value types are numbers, booleans, bytes, characters, enumerations, and some basic structures such as DateTime , Guid , or T...

Distributed Isolator

Update: see my  other post  on references scanning , and  this one  on Docker. Introduction The purpose of Isolator , my framework for running isolated (sandboxed) code is to be able to, well, run code (known as plugins) on distributed, isolated instances (hosts). I initially created two isolation hosts: Process ( ProcessIsolationHost ): a new process is created to host and run the plugin Assembly Load Context ( AssemblyLoadContextIsolationHost ): a new assembly and assembly load context are created to host and run the plugin Now I'm introducing a new one, that allows to execute code on another machine:  ClientIsolationHost . I'll show you how to use it now. Client Host Isolation The idea is to be able to run code on a different machine, while keeping the same capabilities: We pass an existing plugin instance to the host which is then handled transparently Modified context properties are returned from the host to the caller Standard out...

Working with Strings in .NET

Introduction So, by now you should know all there is to about string concatenation  in .NET and the  StringBuilder  class and the  string.Concat  method. I'm not going to cover that here, but, instead, some less known functionality around strings that can (also) bring some performance advantages. Searching When it comes to searching for values ("needles") inside a string ("haystack"), we have a couple options: Using the built-in string methods, such as  string.IndexOf , string.IndexOfAny , string.Contains The ContainsAny extension that works with memory spans Using regular expressions with  Regex , for more advanced pattern matching Since .NET 8, we have another one: the  SearchValues<T>  class. This one is optimised for searching for one or multiple strings (exact values) inside of a string. During its creation, it parses the string and builds a memory model that is suitable for searching. With time, using  SearchValues<T...

C# Magical Syntax

Introduction This post is an update to an old one on my  old blog  and it was inspired by my latest posts on C# versus Java . You may not have realized that some of the patterns that you’ve been using for ages in your C# programs are based on conventions, rather than on a specific API. What I mean by this is, some constructs in C# are based on some magical methods with well-defined names which are not defined in any base class or interface, but yet just work. Let’s see what they are. Enumerating Collections You are probably used to iterating through collections using the foreach statement. If you are, you may know that foreach actually wraps a call to a method called GetEnumerator , like the one that is defined by the IEnumerable and IEnumerable<T> interfaces. Thus, you might think, the magic occurs because the collection implements one or the two, but you would be wrong: it turns out that in order to iterate through a class using foreach all it takes is that the c...

Java vs C# - Part 2

Introduction This is part two of a series of posts on Java and C#, the first part is available here . This time, I am going to talk about a lot of things that weren’t covered before, and leave some stuff for future posts! I'm covering: Object and collection initialization Casts Methods Operator overloading Attributes/annotations Exceptions Iterations Returning enumerables Lambda functions Expression trees Auto closing blocks Object and Collection Initialization C# offers an interesting syntax for initializing instance properties at the same time a variable is declared, which can be combined with parameterized constructors: MyClass c = new MyClass( "constructor argument" ){ OneProperty = 1, AnotherProperty = "two" }; It also offers a syntax for defining the values of a collection upon declaration, including dictionaries (indexed collections): var list1 = new List< string > { "A" , "B" , "C" }; List< string > list2 = [...