Content Developer II at Microsoft, working remotely in PA, TechBash conference organizer, former Microsoft MVP, Husband, Dad and Geek.
121702 stories
·
29 followers

C# 13 Params Collections

1 Share

With the version 17.10.0 Preview 3.0 of Visual Studio Preview you can test some new C# 13 features. In this blog I will explain the params Collection feature as documented in this proposal. To use this feature you have to set the LangVersion in your csproj file to preview.

<Project Sdk="Microsoft.NET.Sdk">
	<PropertyGroup>
		<OutputType>Exe</OutputType>
		<TargetFramework>net8.0</TargetFramework>
		<ImplicitUsings>enable</ImplicitUsings>
		<Nullable>enable</Nullable>
		<LangVersion>preview</LangVersion>
	</PropertyGroup>
</Project>

In C#, the `params` keyword allows a method to accept a variable number of arguments, providing flexibility in how many parameters you pass without needing to define multiple method overloads. This can make your code more concise and easier to maintain. For instance, it's particularly useful when the exact number of inputs is not known in advance or can vary. Moreover, it simplifies the calling code, as you can pass an array or a comma-separated list of arguments that the method will interpret as an array.

From C# 1.0 till 12.0 params parameter must be an array type. However, it might be beneficial for a developer to be able to have the same convenience when calling APIs that take other collection types. For example, an ImmutableArray<T>, ReadOnlySpan<T>, or plain IEnumerable. Especially in cases where compiler is able to avoid an implicit array allocation for the purpose of creating the collection (ImmutableArray<T>, ReadOnlySpan<T>, etc). This saves Heap memory allocation which improves the performance. The Garbage collector doesn't have to free this memory.

C# 1.0 params array

Lets start with an example of an old-school params array parameter in a Sum method. 

internal class Program {

    static void Main(string[] args) {
        Console.WriteLine(Sum(1, 2, 3, args.Length));
    }

    private static Sum(params int[] values) {
        int sum = 0;
        foreach (var item in values) {
            sum += item;
        }
        return sum;
    }
}

When you decompile this code using a tool like ILSpy or the SharpLab.io website you see that an array of int[4] is created in the Main() method (line 5). This is heap allocation which is something you can/should avoid.

internal class Program
{
    private static void Main(string[] args)
    {
        int[] array = new int[4];
        RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
        array[3] = args.Length;
        Console.WriteLine(Sum(array));
    }

    private static int Sum(params int[] values)
    {
        int num = 0;
        int num2 = 0;
        while (num2 < values.Length)
        {
            int num3 = values[num2];
            num += num3;
            num2++;
        }
        return num;
    }
}

C# 13 params Collections

In the next example the Sum() method is using a params ReadOnlySpan<int> parameter in line 7. Nothing else is changed. 

internal class Program {

    static void Main(string[] args) {
        Console.WriteLine(Sum(1, 2, 3, args.Length));
    }

    private static int Sum(params ReadOnlySpan<int> values) {
        int sum = 0;
        foreach (var item in values) {
            sum += item;
        }
        return sum;
    }
}

When you decompile this code you see a  <>y__InlineArray4<int> value is used in the Main() method (line 6). This is a struct which is created by the compiler. It uses the Inline Arrays feature of C# 12. Structs are allocated on the Stack so this code doesn't allocate any heap memory.

internal class Program
{
    [NullableContext(1)]
    private static void Main(string[] args)
    {
        <>y__InlineArray4<int> buffer = default(<>y__InlineArray4<int>);
        <PrivateImplementationDetails>.InlineArrayElementRef<<>y__InlineArray4<int>, int>(ref buffer, 0) = 1;
        <PrivateImplementationDetails>.InlineArrayElementRef<<>y__InlineArray4<int>, int>(ref buffer, 1) = 2;
        <PrivateImplementationDetails>.InlineArrayElementRef<<>y__InlineArray4<int>, int>(ref buffer, 2) = 3;
        <PrivateImplementationDetails>.InlineArrayElementRef<<>y__InlineArray4<int>, int>(ref buffer, 3) = args.Length;
        Console.WriteLine(Sum(<PrivateImplementationDetails>.InlineArrayAsReadOnlySpan<<>y__InlineArray4<int>, int>(ref buffer, 4)));
    }

    private static int Sum([ParamCollection] ReadOnlySpan<int> values)
    {
        int num = 0;
        ReadOnlySpan<int> readOnlySpan = values;
        int num2 = 0;
        while (num2 < readOnlySpan.Length)
        {
            int num3 = readOnlySpan[num2];
            num += num3;
            num2++;
        }
        return num;
    }
}

}

[StructLayout(LayoutKind.Auto)]
[InlineArray(4)]
internal struct <>y__InlineArray4<T>
{
    [CompilerGenerated]
    private T _element0;
}

Benchmark

To compare the performance between the two I have created this Benchmark using BenchmarkDotNet. It compares the Sum of 5 decimals using old-school params arrays and params ReadOnlyCollection<decimal>.

using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

BenchmarkRunner.Run<BM>();

[MemoryDiagnoser(false)]
[HideColumns("RatioSD", "Alloc Ratio")]
//[ShortRunJob]
public class BM {

    private decimal _value = 500m;

    [Benchmark]
    public decimal CallSumArray() => SumArray(1m, 100m, 200m, 300m, 400m, _value);

    [Benchmark(Baseline = true)]
    public decimal CallSumSpan() => SumSpan(1m, 100m, 200m, 300m, 400m, _value);

    private static decimal SumArray(params decimal[] values) {
        decimal sum = 0;
        foreach (var item in values) {
            sum += item;
        }
        return sum;
    }

    private static decimal SumSpan(params ReadOnlySpan<decimal> values) {
        decimal sum = 0;
        foreach (var item in values) {
            sum += item;
        }
        return sum;
    }  
}

The CallSumSpan method is 28% faster and doesn't allocate any heap memory. The CallSumArray method allocated 120 bytes.

Benchmark summary

Don't want to wait for C# 13

If you don't want to wait for C# 13 you can already use a solution with simular results in C# 12. You can use Collection Expression with a normal ReadOnlySpan<T> parameter. A collection expression contains a sequence of elements between [ and ] brackets, see line 4. 

internal class Program {

    static void Main(string[] args) {
        Console.WriteLine(Sum([1, 2, 3, args.Length]));
    }

    private static int Sum(ReadOnlySpan<int> values) {
        int sum = 0;
        foreach (var item in values) {
            sum += item;
        }
        return sum;
    }
}

When you decompile this code you see the same code you saw when you used the params ReadOnlyCollection<decimal>.

Closure

In this blog post I showed you the new 'params Collection' feature in C# 13, available in Visual Studio Preview 17.10.0 Preview 3.0. It explains how to enable the feature by setting 'LangVersion' to preview in the project file and delves into the benefits of using 'params' with collection types other than arrays, like 'ReadOnlySpan<T>'. This enhancement aims to improve performance by reducing heap memory allocations, thus easing the workload on the garbage collector. The post includes an example of the traditional 'params array' in a `Sum` method to illustrate the concept.

Hopefully Microsoft will add in .NET 9 (and later) more overloads with 'params ReadOnlySpan<T>' to the methods which are using 'params arrays'. For example the String.Split method.

 

Read the whole story
alvinashcraft
1 hour ago
reply
West Grove, PA
Share this story
Delete

New memory variants for the Raspberry Pi Compute Module family

1 Share

Since 2014, we have provided the power of Raspberry Pi in a flexible form factor designed specifically for industrial and embedded applications, and we’ve been surprised and delighted to see the incredible variety of ways in which our customers use Raspberry Pi Compute Modules. Today, we are pleased to announce that we have expanded our Compute Module 4S offering: these industrial boards are now available with additional SDRAM, and as well as the original 1GB variant, you can now choose from 2GB, 4GB, and 8GB options.


This is an image of a Raspberry Pi compute module. It's a compact, single-board computer with various electronic components visible. The green circuit board has multiple chips and connectors soldered onto it, and you can see the Raspberry Pi logo as well as other certification marks. At the center is a large, square processor chip, and there's a smaller, rectangular chip likely for memory. There are also various smaller components and connectors that are part of the board's circuitry. The module is designed to be integrated into other devices as a computing core.
Raspberry Pi Compute Module 4S

Compute Module 4S is based on the Raspberry Pi 4 architecture. We designed it for industrial customers who are migrating from Compute Module 3 or Compute Module 3+, and who are looking to retain the same form factor but would like greater computing power and more memory.

We will keep Compute Module 4S in production until at least January 2034, and we have produced a transition document specially to help users migrate to it from Compute Module 1, Compute Module 3, or Compute Module 3+. A full product brief and datasheet are also available.


This is an image of a Raspberry Pi compute module. It's a compact, single-board computer with various electronic components visible. The green circuit board has multiple chips and connectors soldered onto it, and you can see the Raspberry Pi logo as well as other certification marks. At the center is a large, square processor chip, and there's a smaller, rectangular chip likely for memory. There are also various smaller components and connectors that are part of the board's circuitry. The module is designed to be integrated into other devices as a computing core.
Ask your Approved Reseller if our Compute Module 4S Lite variant may better suit your needs

Compute Module 4S boards are in stock and available now from our Approved Resellers for industry, with a maximum lead time of six weeks. These modules are supplied only in bulk 200-unit boxes, with prices per unit starting from $25 US. Find your local Raspberry Pi Approved Reseller for industry and contact them directly to discuss sales.

What is Compute Module 4S used for?

Our industrial customers have used these boards in everything from electric vehicle charging stations to self-pour beer taps and coffee machines. We’ve also seen specialised medical monitoring devices built around our Compute Modules. A market research customer of ours used the modules to develop a system that understands the types of TV programmes different people enjoy watching, and Kunbus has developed an entire industrial product line, Revolution Pi, around our Compute Module.

Browse our customer success stories for plenty more examples of all types of Raspberry Pi product in use in business and industry. You’ll find everything from farming and factory automation to digital signage and earthquake monitoring. And to make sure you don’t miss any news about Raspberry Pi for industry, sign up to receive our quarterly updates for business customers.

The post New memory variants for the Raspberry Pi Compute Module family appeared first on Raspberry Pi.

Read the whole story
alvinashcraft
6 hours ago
reply
West Grove, PA
Share this story
Delete

Jeremy Sinclair

1 Share

Jeremy is a Windows Developer MVP, Avalonia MVP, and Arm Ambassador who mostly focuses on all things Windows on Arm. He is a member of the .NET Foundation Project Committee and is also a member of the selection committee for .NET on AWS FOSS Fund.

He enjoys making contributions to OSS to help move projects forward and to ensure that Arm support is a first-class citizen.

You can find Jeremy on the following sites:

PLEASE SUBSCRIBE TO THE PODCAST

You can check out more episodes of Coffee and Open Source on https://www.coffeeandopensource.com

Coffee and Open Source is hosted by Isaac Levin

--- Support this podcast: https://podcasters.spotify.com/pod/show/coffeandopensource/support



Download audio: https://anchor.fm/s/63982f70/podcast/play/85821990/https%3A%2F%2Fd3ctxlq1ktw2nl.cloudfront.net%2Fstaging%2F2024-3-23%2F375340212-44100-2-45b443dd0e37b.mp3
Read the whole story
alvinashcraft
6 hours ago
reply
West Grove, PA
Share this story
Delete

Windows 11 Start menu ads are now rolling out to everyone

1 Share
Start menu ads in Windows 11
The app recommendations in the Windows 11 Start menu. | Image: Microsoft

Microsoft is starting to enable ads inside the Start menu on Windows 11 for all users. After testing these briefly with Windows Insiders earlier this month, Microsoft has started to distribute update KB5036980 to Windows 11 users this week, which includes “recommendations” for apps from the Microsoft Store in the Start menu.

“The Recommended section of the Start menu will show some Microsoft Store apps,” says Microsoft in the update notes of its latest public Windows 11 release. “These apps come from a small set of curated developers.” The ads are designed to help Windows 11 users discover more apps, but will largely benefit the developers that Microsoft is trying to tempt into building more Windows apps.

Microsoft only started testing...

Continue reading…

Read the whole story
alvinashcraft
6 hours ago
reply
West Grove, PA
Share this story
Delete

Get Better at Using Prompts With Deliberate Practice: One technical writer's little experiment -- by Diana Cheung

1 Share
In this guest post, Diana Cheung explores how to learn AI by using deliberate practice to enhance her prompting skills. In her deliberate practice, she emphasizes the importance of intentional, systematic practice rather than mindless repetition, similar to how one would learn coding or other skills.
Read the whole story
alvinashcraft
6 hours ago
reply
West Grove, PA
Share this story
Delete

General Performance: Choosing Between GetValueOrDefault() and Coalesce Operator for Nullable Integers

1 Share
In dealing with nullable integers and the need for default values, two common approaches are the coalesce operator (??) and GetValueOrDefault(). Alternatively, utilizing HasValue with the conditional operator is demonstrated.







Read the whole story
alvinashcraft
6 hours ago
reply
West Grove, PA
Share this story
Delete
Next Page of Stories