.NET 9 Features
//Before .NET 9
public static void PrintNumbers( params int[] numbers)
{
Console.WriteLine("Numbers in Array: " + string.Join(", ", numbers));
}
public static void PrintNumbers(List numbers)
{
Console.WriteLine("Numbers in List: " + string.Join(", ", numbers));
}
// .NET 9
public static void PrintNumbersInNET9(params ReadOnlySpan numbers)
{
Console.WriteLine("Numbers in ReadOnlySpan: " + string.Join(", ", numbers.ToArray()));
}
public static void PrintNumbersInNET9(params IEnumerable numbers)
{
Console.WriteLine("Numbers in IEnumerable: " + string.Join(", ", numbers));
}
Call those methods just like below.
// Using params with a Array or List
var numbersList = new List { 6, 7, 8 };
ParamsCollection.PrintNumbers(numbersList.ToArray());
ParamsCollection.PrintNumbers(numbersList);
// Using params with ReadOnlySpan
ParamsCollection.PrintNumbersInNET9([6, 7, 8]);
// Using params with List
ParamsCollection.PrintNumbersInNET9(numbersList.Where(x => x > 6));
The aforesaid scenario where you have two method overloads: one accepting params IEnumerable<T> and another taking params ReadOnlySpan<T>. The method resolution works as follows:
params ReadOnlySpan<T> overload is chosen.params ReadOnlySpan<T> overload is also selected, since arrays can be implicitly converted to ReadOnlySpan<T>.List<T> is passed, the params IEnumerable<T> overload is preferred, as List<T> implements IEnumerable<T> but does not have an implicit conversion to ReadOnlySpan<T>..ToArray() and .ToList() inherently introduce additional resource overhead. However, the updated implementation now supports passing Span<> and IEnumerable<>, optimizing memory usage and enabling lazy execution. This enhancement improves efficiency while offering greater flexibility for performance-critical scenarios.
public int EmplSalary { get; set; }, _empSalary) and internal getter/setter methods (void set_EmplSalary(int empSalary) and int get_EmplSalary()). field keyword, which allows direct access to the backing field without the need for manual definition.
private int _empSalary;
public int EmpSalary
{
get => _empSalary;
set
{
if (value <= 0)
throw new ArgumentOutOfRangeException(nameof(value),
"Salary must be greater than 0");
_empSalary = value;
}
}
public int EmployeeSalary
{
get => field;
set
{
if (value <= 0)
throw new ArgumentOutOfRangeException(nameof(value),
"Salary must be greater than 0");
field = value;
}
}
public async Task TaskWhenEachFeature()
{
// Before
var tasks1 = Enumerable.Range(1, 5)
.Select(async i =>
{
await Task.Delay(1000);
return $"Task is {i} done in earlier.";
})
.ToList();
while (tasks1.Count > 0)
{
var completedTask = await Task.WhenAny(tasks1);
tasks1.Remove(completedTask);
Console.WriteLine(await completedTask);
}
// .NET 9 USAGE OF Task.WhenEach feature
Console.WriteLine("==.NET9 - Task.WhenEach feature");
var tasks2 = Enumerable.Range(1, 5)
.Select(async i =>
{
await Task.Delay(2000);
return $"Task In .NET9 {i} done";
})
.ToList();
await foreach (var completedTask in Task.WhenEach(tasks2))
Console.WriteLine(await completedTask);
}
public static void SearchValuesFeature()
{
var message = "Explore new feature of SearchValues improvements in .NET9".AsSpan();
// .NET 8
var charSearch = SearchValues.Create(['.','N', 'E', 'T']);
Console.WriteLine(message.ContainsAny(charSearch));
// .NET 9
var wordSearch = SearchValues.Create([".NET9", "of"], StringComparison.OrdinalIgnoreCase);
Console.WriteLine(message.ContainsAny(wordSearch));
}
var guid = Guid.NewGuid(); // v4 UUID
var guidv7 = Guid.CreateVersion7(); // v7 UUID
var guidList = new List
{
Guid.CreateVersion7(TimeProvider.System.GetUtcNow()),
Guid.CreateVersion7(TimeProvider.System.GetUtcNow().AddMinutes(-10)),
Guid.CreateVersion7(TimeProvider.System.GetUtcNow().AddMinutes(10)),
Guid.CreateVersion7(TimeProvider.System.GetUtcNow().AddMinutes(-20))
};
//write the guids in whatever list contains.
foreach (var v7guid in guidList)
{
Console.WriteLine(v7guid.ToString());
}
Console.WriteLine("=====================");
//Order the guidlist and then write list.
//The result you can identify guids are ordered based on creation time.
var sortedList = guidList.OrderBy(x => x).ToList();
foreach (var v7guid in sortedList)
{
Console.WriteLine(v7guid.ToString());
}
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
}
var employees = new List {
new Employee(){ Id = 11, Name = "Ram" },
new Employee(){ Id = 12, Name = "Bheem" },
new Employee(){Id = 13, Name = "Lakshman"},
new Employee(){Id = 14, Name = "Hanu"},
new Employee(){Id = 15, Name = "Dev"},
new Employee(){Id = 16, Name = "Nandan"},
new Employee(){Id = 17, Name = "Krish"},
new Employee(){Id = 18, Name = "Hash"},
};
foreach ((int index, Employee emp) in employees.Index())
{
Console.WriteLine($"Index: {index}, Employee Name: {emp.Name}");
}
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public int YearJoin { get; set; }
public int JobLevel { get; set; }
public int MeritPoints { get; set; }
}
var employees = new List {
new Employee(){ Id = 11, Name = "Ram", YearJoin = 2015, JobLevel = 6, MeritPoints = 10 },
new Employee(){ Id = 12, Name = "Bheem", YearJoin = 2012, JobLevel = 5, MeritPoints = 20 },
new Employee(){Id = 13, Name = "Lakshman", YearJoin = 2015, JobLevel = 6, MeritPoints = 30},
new Employee(){Id = 14, Name = "Hanu", YearJoin = 2016, JobLevel = 6, MeritPoints = 40},
new Employee(){Id = 15, Name = "Dev", YearJoin = 2024, JobLevel = 6, MeritPoints = 50},
new Employee(){Id = 16, Name = "Nandan", YearJoin = 2012, JobLevel = 5, MeritPoints = 60},
new Employee(){Id = 17, Name = "Krish", YearJoin = 2012, JobLevel = 5, MeritPoints = 70},
new Employee(){Id = 18, Name = "Hash", YearJoin = 2015, JobLevel = 6, MeritPoints = 80},
};
//BEFORE .NET 9 Example
// Aggregate MeritPoints by Job Level using GroupBy and Aggregate
var meritPointsByEmpJobLevel = employees
.GroupBy(user => user.JobLevel) // Group users by their Job Level
.Select(group => new
{
JobLevel = group.Key,
TotalMeritPoints = group.Sum(user => user.MeritPoints)
}
); // Aggregate Merit Points for each Job Level
// Print the results
foreach (var jobLevelAggregate in meritPointsByEmpJobLevel)
{
Console.WriteLine($"Total merit points per each employee level " +
$"{jobLevelAggregate.JobLevel} is {jobLevelAggregate.TotalMeritPoints}");
}
var totalEmpMeritPointsByLevel = employees.AggregateBy(e => e.JobLevel,
seed: 0, (acc, meritPoints) => acc + meritPoints.MeritPoints);
foreach (var meritPointByLevel in totalEmpMeritPointsByLevel)
{
Console.WriteLine($"Total merit points per each employee level " +
$"{meritPointByLevel.Key} is {meritPointByLevel.Value}");
}
IEnumerable<(TKey Key, TAccumulate Aggregate)> AggregateBy(
this IEnumerable source,
Func keySelector,
Func seedFactory,
Func aggregator
);
Introduction
.NET 9 is the latest version of Microsoft's released in Nov 2024. Its open-source development platform for building applications for web, mobile, desktop and cloud environments.
This release is pack of many new features, LINQ methods and performance improvements and many more.
About
In this post, we are focusing about one of new LINQ method introduced in .NET 9. Its very useful, comprehensive and easily can understand and can be used in our project as well :).
So, Lets start explore on this.
Scenario
Lets consider a easy scenario as "To get employees count based on the year joined".
Employee Class:
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public int YearJoin { get; set; }
}
Setup Employee List with Sample Data
var employees = new List<Employee> {
new Employee(){ Id = 11, Name = "Ram", YearJoin = 2015 },
new Employee(){ Id = 12, Name = "Bheem", YearJoin = 2012 },
new Employee(){ Id = 13, Name = "Lakshman", YearJoin = 2015 },
new Employee(){ Id = 14, Name = "Hanu", YearJoin = 2016 },
new Employee(){ Id = 15, Name = "Dev", YearJoin = 2024 },
new Employee(){ Id = 16, Name = "Nandan", YearJoin = 2012 },
new Employee(){ Id = 17, Name = "Krish", YearJoin = 2012 },
new Employee(){ Id = 18, Name = "Hash", YearJoin = 2015 },
};
So, First let us understand - How we are doing currently (Earlier to .NET 9).
Before .NET 9
Approach is - Grouping and Counting
1. GroupBy: Groups the employees based on their value provided (Year).
2. Select(g => new {Key = g.Key, Value = g.Count()}}: project each group into anonymous object with two properties.
.NET 9
In .NET 9 -Its simplifies the process and streamlined code like below.
CountBy Benefits
Header of the site
Copyright Ramchand @2014
(function() {
var app = angular.module("DemoClickApp", []);
var DemoController = function($scope) {
$scope.Search = function(empname) {
if (empname)
$scope.result = "You have searched for " + empname;
else
$scope.result = "Please enter employee name";
};
};
app.controller("DemoController", DemoController);
})();
List of Emplooyees
(function() {
var app = angular.module("DemoRepeatApp", []);
var DemoController = function($scope) {
var sampleEmployees = '[' +
'{ "Name":"Ramchand" , "Designation":"SSE" , "Location":"Bhubhaneswar" },' +
'{ "Name":"Lakshman" , "Designation":"DBA" , "Location":"Noida" },' +
'{ "Name":"ABC" , "Designation":"Team Lead" , "Location":"Banglore" } ]';
$scope.employees = JSON.parse(sampleEmployees);
};
app.controller("DemoController", DemoController);
})();
Welcome to Angular Application
This div is controlled by Angular JS: {{ 1 + 2 }}
To Display Constants / Static ones in Angular JS: {{ '1 + 2' }}
Normal div doesn't handled by Angular JS: {{ 1 + 2 }}
{{ angularjs }}
var WelcomeAngular = function($scope) {
$scope.angularjs = "Welcome to Angular Js";
};
var app = angular.module("DemoApp", [])
app.controller('DemoController', WelcomeAngular);
Employee Search
Employee Search
namespace UsersSkypeStatusInMVC.Models
{
///
/// User Model
///
public class UserModel
{
public int UserId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string SkypeId { get; set; }
public string ProfileImagePath { get; set; }
}
}
using System.Collections.Generic;
using System.Web.Mvc;
using UsersSkypeStatusInMVC.Models;
namespace UsersSkypeStatusInMVC.Controllers
{
public class AdminController : Controller
{
// GET: UsersProfile
public ActionResult UserProfiles()
{
List usersList = GetUsers();
return View(usersList);
}
///
/// Get the list of sample users
///
/// User List
private List GetUsers()
{
var usersList = new List
{
new UserModel
{
UserId = 1,
Name="Ramchand",
Email = "ram@abc.com",
SkypeId = "ramchand.repalle", // Skype Id
ProfileImagePath = "Ramchand.jpg"
},
new UserModel
{
UserId = 2,
Name="Abc",
Email = "chand@abc.com",
SkypeId = "abctest",// Skype Id
ProfileImagePath = "abc.jpg"
},
new UserModel
{
UserId = 3,
Name="def",
Email = "def@abc.com",
SkypeId = "ram",// Skype Id
ProfileImagePath = "def.jpg"
}
};
return usersList;
}
}
}
@model IEnumerable@{ ViewBag.Title = "User Profiles"; } User Profiles
@foreach (var item in Model) { var skypeId = @Html.DisplayFor(modelItem => item.SkypeId); var profileImg = "../../Images/" + @Html.DisplayFor(modelItem => item.ProfileImagePath);}@Html.DisplayFor(modelItem => item.UserId)
@Html.DisplayFor(modelItem => item.Name)
@Html.DisplayFor(modelItem => item.Email)
![]()
![]()
![]()