DEV Community

Cover image for Leaked C# 12 Preview 3 Features! Worth the Wait or Not?
ByteHide
ByteHide

Posted on • Originally published at bytehide.com

Leaked C# 12 Preview 3 Features! Worth the Wait or Not?

It’s a great day to explore C# 12 Preview 3 features. We’ll be diving into interesting updates like the enhanced nameof, efficient Inline Arrays and the innovative Interceptors. Grab a comfy seat and let’s hop into this coding journey!

Using nameof to Reach for instance members

Ever felt super annoyed writing lots of nameof to access instance members? Well, C# 12 Preview 3 brings a relief for you. Let’s see how this magic works:

Remember, earlier, when trying to use nameof keyword with an instance field, you had to have an instance of the object, right?

Well, say goodbye to those restrictions! Now, with C# 12 Preview 3, we can do that just with the class.

Given a practical example, let’s see how this unique feature comes into play in this piece of code:

internal class NameOf
{
    public string S { get; } = "";
    public static int StaticField;
    public string NameOfLength { get; } = nameof(S.Length);
    public static void NameOfExamples()
    {
        Console.WriteLine(nameof(S.Length));       // Using `nameof` with instance member
        Console.WriteLine(nameof(StaticField.MinValue));  // Using `nameof` with static field
    }
    [Description($"String {nameof(S.Length)}")]
    public int StringLength(string s)
    { return s.Length; }
}
Enter fullscreen mode Exit fullscreen mode

Did you see how nameof behaves with S.Length and StaticField.MinValue? That’s new in C# 12 Preview 3! You don’t need an instance to get the name of S.Length. You can also get StaticField.MinValue using nameof.

In simple terms, imagine having a toy box called “NameOf”. Previously, you had to climb into the box to get your favorite toy.

But now? You can just tell your magic box what you want (like the length of the string rubix cube, or the minimum number of ballet teddies), and it gives it to you, without even entering! Cool, right?

Stay tuned, because we have many more exciting features to reveal! Are you as excited as I am?

Exploring Inline Arrays

Inline arrays are like that sporty car you always wanted: compact, stylish, and fast! This feature is a buff to your code’s performance, without the need for any extensive modification of your existing code.

Take a look at this example that unveils how the revamped compiler creates a unique IL for accessing inline arrays:

private static void InlineArrayAccess(Buffer10<int> inlineArray)
{
    for (int i = 0; i < 10; i++)
    {
        inlineArray[i] = i * i;   // Accessing Inline Array just like any other arrays
    }
    foreach (int i in inlineArray)  // Iterating through Inline Array as usual
    {
        Console.WriteLine(i);
    }
}
Enter fullscreen mode Exit fullscreen mode

In this case, both the accessing and iterating of inline arrays are akin to regular arrays, but with a distinctive underlying IL carrying the potential for a performance surge.

Creating inline arrays could appear daunting when you first encounter it, but it’s important to remember, the bulk of us will be benefiting from the performance enhancements of these arrays more than creating them. Besides, it never hurts to know the logistics behind your tools, does it?

Visualise an inline array as a neatly arranged chest of drawers. The accessibility is swift because every drawer is made to a stipulated size. It’s analogous to a type marked with the InlineArrayAttribute, defining the array size or the quantity of these drawers.

Here’s what creating an inline array looks like:

[System.Runtime.CompilerServices.InlineArray(10)] // Specifies length of the array
public struct Buffer10<T>
{
    private T _element0;  // The only field in the array
}
Enter fullscreen mode Exit fullscreen mode

Buffer10<T> here is like a chest with exactly ten drawers, thanks to the InlineArray attribute specifying the length.

So, inline arrays are here to rev up your code’s runtime performance! Ready to tap into performance gains with your arrays? I bet you are!

Experimental Interceptors: A Peak into the Future

The concept of interceptors, even though experimental at this stage, is a thrilling development aimed at advanced users and situations. This feature facilitates better Ahead Of Time (AOT) compilation- like a time travel ticket which lets you compile before you would normally.

Sound odd? Let me simplify it further. Think of interceptors as clever code tacticians that allow for detouring method calls to alternate streams of code. By outlining particular attributes, you get to lead the way. Just remember, these adept interceptors are designed primarily with source generators in mind.

Okay, enough with the theoretical stuff. Let’s see how to enable these in your project file:

<PropertyGroup>
   <Features>InterceptorsPreview<Features>
</PropertyGroup>
Enter fullscreen mode Exit fullscreen mode

What this little snippet of code does is like enabling a secret superpower. Now that they’re on, let’s see what wonders those Interceptors can perform:

  • Are you dealing with compile time known calls like Regex.IsMatch(@"a+b+")? Interceptors can efficiently handle this by using statically-generated code. Think of it like Morse Code, where a certain pattern sends out specific signals- but in this case, you’re optimizing for AOT.
  • They love ASP.NET Minimal API calls! For example, app.MapGet("/products", handler: (int? page, int? pageLength, MyDb db) => { ... }) can be intercepted to register a statically-generated thunk. Like a friendly mailman, the interceptor will directly deliver your handler, skipping allocations and indirections.
  • In vectorization, interceptors are the skilled craftsman, rewriting code for checking and using relevant intrinsics at runtime.
  • Moreover, they lend a hand in resolving the static dependency graph when it comes to dependency injection.. Our little ninjas can intercept calls like provider.Register<MyService>().
  • They’re translators too! Interceptors can translate calls to query providers into another language (SQL for example) at compile time.
  • And if you’re into serializing, interceptors can generate type specific serialization based on Serialize<MyType>() calls, again, all at compile time!

Remember, Interceptors, as of now, are like the special guest stars of the show. Experimental yet promising, they are planned for just .NET 8. But, who knows? They might become a regular feature in future C# updates! Exciting, isn’t it?

And there we have it! We’ve looked at key features of C# 12 Preview 3, including the smarter nameof, speedy Inline Arrays, and the experimental Interceptors.

Each of these additions will undeniably improve our coding. That’s the beauty of progress. So, keep your eyes peeled for future updates and continue to sharpen those coding skills. Happy coding till we meet again!

Top comments (2)

Collapse
 
rosselm profile image
Martin Rosselle

where does adding features stop... in the end you cannot keep adding features to a language

Collapse
 
drleh profile image
Devon Lehman

Sure you can! New features don't always need to be learned by every developer. 99% of devs will never need interceptors but that 1% will be able to turn that into a huge performance boost or give you the ability to AOT compile your code for a specific platform.

There's always going to be ways to improve the language to make the code better, faster, easier to read, easier to write, etc.