#Net5 – C#9 “records” and “deconstruction” super cool feature 🆒🆒🆒

Buy Me A Coffee

Hi !

I’m still learning about C#9, and there is a lot to learn about records. And, between all this information, I Just learn a super cool feature related to records: deconstruction.

Let’s start with a simple record definition for a pet. This one includes pet’s name and pet’s age:

public record Pet
{
    public string Name { get; init; }
    public int Age { get; init; }
    public Pet(string name, int age)
        => (Name, Age) = (name, age);
}

This is fine, init only properties (cool feature!) and we can access the values as usual.

static void Main(string[] args)
{
    var pet = new Pet("Goku", 2);

    // get pet info, standard way
    var gokuName = pet.Name;
    var gokuAge = pet.Age;
}

So far, so good. However, if you like clean code, we can improve this a little using some new features in C#9. So, let’s start with much simpler record definition.

public record NewPet(string Name, int Age);

And we can access the pet properties using deconstruction (new term for me!)

// get pet info, C#9 deconstruction
var newPet = new NewPet("Goku", 2);
var (gokuName, gokuAge) = newPet;

I like this new one 👆 too ! I’ll always like features that improves readability and saves us a lot of extra code.

Happy coding!

Greetings

El Bruno


References


¿Con ganas de ponerte al día?

En Lemoncode te ofrecemos formación online impartida por profesionales que se baten el cobre en consultoría:

#Net5 – C#9 “Init-only properties” are super cool 🆒🆒🆒

Buy Me A Coffee

Hi !

So this one does not fit in the line “readability improvement”, however is a nice step in order to write cleaner code. Yes, I know that doesn’t make sense, let me try to explain.

Let’s start with a simple class with 2 properties. Interesting enough the property Age has a new accessor [init] to describe the property as a read-only property:

class Pet
{
  public string Name { get; set; }
  public int Age { get; init; }
}

When we create a new Pet object, we can set the initial value of Age on the construction of the object (object initialization), and that’s it. Otherwise we will get this amazing error.

Error CS8852 Init-only property or indexer 'Program.Pet.Age' can only be assigned in an object initializer, or on 'this' or 'base' in an instance constructor or an 'init' accessor. 
Csharp9 init only properties

Until C#9, the properties in a class need to be mutable in order to support Object Initialization. And that means some extra code in the property-set definition in order to support read-only properties. Now in C# 9, this is solved with the [init] accessor 😁😁😁

I like this new one 👆 ! Not a great readability improvement, but it saves us a lot of extra code.

Happy coding!

Greetings

El Bruno


References


¿Con ganas de ponerte al día?

En Lemoncode te ofrecemos formación online impartida por profesionales que se baten el cobre en consultoría:

#Net5 – C#9 logical operators “is” and “is not” are super cool 🆒🆒🆒

Buy Me A Coffee

Hi !

In the line of good features, that are also nice to read, the new use of is and is not is a huge improvement in readability.

As usual, old school validation for objects and types:

// old school
if(!(testObj is MyClass)) {...}

And now, we can type the validation with some style:

// C# 9 style
if(testObj is not MyClass) {...}

I like this new one 👆, now null / not null and other validations will be the same. With an improed readability !

Happy coding!

Greetings

El Bruno


References


¿Con ganas de ponerte al día?

En Lemoncode te ofrecemos formación online impartida por profesionales que se baten el cobre en consultoría:

#Net5 – C#9 target-typed new expressions are super cool 🆒🆒🆒

Buy Me A Coffee

Hi !

I know I’m late to the party here, however I’m still enjoying some of the new C# 9 features a lot. I just realized that now, I can create objects in a different way, which is still super clear to read.

Disclaimer: some of the new features are cool, however my gut told me that they will make code harder to read. I also understand that I have 20 years of writing C# code in my back, so I need to find the balance here.

As usual, 2 lines of code are the best way to showcase this:

// old school
var pointOldSchool = new System.Drawing.Point(3, 5);

// new school and still very readable
System.Drawing.Point pointCSharpNine = new(3, 5);

// crappy output
Console.WriteLine("Old School: var pointOldSchool = new System.Drawing.Point(3, 5);");
Console.WriteLine(pointOldSchool);

Console.WriteLine("C#9: System.Drawing.Point pointCSharpNine = new(3, 5);");
Console.WriteLine(pointCSharpNine);

This this output as expected:

Old School: var pointOldSchool = new System.Drawing.Point(3, 5);
{X=3,Y=5}
C#9: System.Drawing.Point pointCSharpNine = new(3, 5);
{X=3,Y=5}

I like this new one 👆

Happy coding!

Greetings

El Bruno


References


¿Con ganas de ponerte al día?

En Lemoncode te ofrecemos formación online impartida por profesionales que se baten el cobre en consultoría:

#Podcast – NTN 76 – Feliz Año Nuevo 🎉 con todas las novedades de #Net5 !

Buy Me A Coffee

Buenas!

Feliz Año Nuevo 🎉🎉🎉, empezamos el año dando un repaso a todas las novedades de Net 5 con el gran amigo Miguel Teheran. Comentamos un poco la historia de Net y como Net 5 es el primer paso para la unificación de todos los .Net Frameworks que conocemos.

También hablamos un poco de los lenguajes, de las novedades de C#9, del estado de F# y del pobre VB.Net, donde todos coincidimos que está un poco abandonado.

Gracias y felices fiestas !

Speakers

  • Miguel Teheran es Developer and Software Consultant (LinkedIn)
  • Juan Carlos Quijano Abad es Microsoft Certified Trainer, Arquitecto de Soluciones en Azure, Consultor independiente en implantación de DevOps (LinkedIn)
  • Bruno Capuano es Canada Innovation Lead at Avanade and Microsoft AI MVP (LinkedIn)

Ir a descargar

Resources

Happy coding!

Greetings

El Bruno



¿Con ganas de ponerte al día?

En Lemoncode te ofrecemos formación online impartida por profesionales que se baten el cobre en consultoría:

#Net5 – C#9 “records”, “with” and “this”, a super cool mix 🆒🆒🆒

Buy Me A Coffee

Hi !

Our next podcast episode is focused on .Net 5. We had an amazing chat around a lot of features, and of course, C# 9 was part of the conversation.

I got this amazing post [C# 9.0: Records – Work With Immutable Data Classes] from Tomas Huber, in my reading notes and working with records is something that I wanted to test.

In a few words, a record is an immutable class. Which is super cool, because it allows some cool operations for mapping, reflection and more. Again, please read Tomas post.

On of the features of records is that once, you define a record with a constructor, there is no default constructor anymore. Let’s start with a simple person record with 3 properties for Name, Age and Married status (as boolean)

public record PersonRecord(string Name, int Age, bool Married)
{
    public override string ToString() => 
        $"Name: {Name} - Age: {Age} - Married: {Married}";
}

Losing the default constructor can be a challenge if we want to copy a record. However we can take advantage of the with expression and create new objects that uses the protected copy constructor. Let’s take a look at the same person object with a CopyUsingMarriedTrue() function that, creates a new object with the same properties changing the value of the Married property.

public record PersonRecord(string Name, int Age, bool Married = false)
{
    public Guid Id { get; init; } = Guid.NewGuid();
    public override string ToString() => 
        $"Name: {Name} - Age: {Age} - Married: {Married} - Guid: {Id}";

    public PersonRecord CopyUsingMarriedTrue() => this with { Married = true };
}

Now it’s time for a full Console test, where I create a couple of persons and check the values of the person. Important, I added a Guid Id property to test the copy and constructor behavior.

  • Lines 14 to 18, I created a Bruno person with Married as True, and I created a BrunoMarried to check the new created object.
  • Lines 20 to 25, I created a Valentino person with Married as False and I created a ValentinoMarried to check the new created object.
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("start");
var bruno = new PersonRecord("Bruno", 40, true);
Console.WriteLine($"{bruno.ToString()}");
Console.WriteLine($"Bruno Is Married created");
var brunoMarried = bruno.CopyUsingMarriedTrue();
Console.WriteLine($"{brunoMarried }");
Console.WriteLine($"———————————–");
var valentino = new PersonRecord("Valentino", 13, false);
Console.WriteLine($"{valentino.ToString()}");
Console.WriteLine($"Valentino Is Married created");
var valentinoMarried = valentino.CopyUsingMarriedTrue();
Console.WriteLine($"{valentinoMarried}");
}
}
public record PersonRecord(string Name, int Age, bool Married = false)
{
public Guid Id { get; init; } = Guid.NewGuid();
public override string ToString() => $"Name: {Name} – Age: {Age} – Married: {Married} – Guid: {Id}";
public PersonRecord CopyUsingMarriedTrue() => this with { Married = true };
}
}

The output is an awesome surprise. I mean, my code always surprise me, however using this feature is an awesome surprise !

start
Name: Bruno - Age: 40 - Married: True - Guid: 82e60022-0fb2-456d-89c0-ab88bef5aff6
Bruno Is Married created
Name: Bruno - Age: 40 - Married: True - Guid: 82e60022-0fb2-456d-89c0-ab88bef5aff6
-----------------------------------
Name: Valentino - Age: 13 - Married: False - Guid: 7acca9e2-f461-4fc9-8e29-06f6f0ffb6c6
Valentino Is Married created
Name: Valentino - Age: 13 - Married: True - Guid: 7acca9e2-f461-4fc9-8e29-06f6f0ffb6c6
csharp 9 with and records

Happy coding!

Greetings

El Bruno


References


¿Con ganas de ponerte al día?

En Lemoncode te ofrecemos formación online impartida por profesionales que se baten el cobre en consultoría:

#Net5 – Migrating a fully functional Windows Form app to Net 5 in 10 minutes !

Buy Me A Coffee

Hi !

TbVolScroll is a super cool project, take a look 👇

Simple utility to enable volume control when your mouse cursor is positioned above the taskbar.
Hold the left ALT key to enable precise volume control (decrease/increase volume by 1%). Standard volume step is 5%. The volume bar will follow the cursor when it’s moved.
By default, if the volume is lower than 10% precise volume control is automatically enabled.

TbVolScroll

Note: As far as I remember, this feature is available in other OS.

And thanks to his author the code of the tool is available in GitHub (see references).

The original project is a .Net Framework 4.7.2 project, so I decided to test how much time it will take to migrate the project to .Net 5. I didn’t perform a deep analysis of the source project, before start. This is my labs migration path

  • Create a new Windows Form Net 5 project named [TbVolScrollNet5]
  • Copy all the files from the original project, avoiding the .csproj file
  • Rebuild !

And it worked ! I mean, I fixed some namespaces, added a missing NuGet package and 10 minutes later it was working. Of course, I submitted a pull request with the migration project, in the meantime I will keep this local just for fun.

And I want to use it ! So now is the time to pack and publish a local version of the tool. I created a local publish profile and defined

  • Build in Release | Any CPU
  • Deployment as Self-Contained
  • Runtime win-x86
  • Produce as single file
  • Enable ReadyToRun compilation
tbvolscroll publish profile as self contained

And that’s it! 150 MB to a fully functional working app 👇😸👇

tbvolscroll published version

Now back to work, and in my next steps I’ll publish this as a clickonce app so it’s easy to distribute. And the perfect excuse to learn more about .Net 5 !

References


¿Con ganas de ponerte al día?

En Lemoncode te ofrecemos formación online impartida por profesionales que se baten el cobre en consultoría:

#OpenCV – Open a video file 🎥 and save each frame as a PNG 🖼 file to a folder 📂#Net5

Buy Me A Coffee

Hi !

A couple of days ago I wrote this post, and made the sample with Python. So today, same scenario, however with C# 9 and Net5.

This is a non-usual scenario, however I’m on a point where I need to extract all the frames from a video file. The reason: some of these frames will be used to train a Machine Learning model.

There are tools that can do this, however it’s a nice moment to do some OpenCV code. Let’s go for it. A couple of remarks

  • Video file must be in the same folder as python file, and the name is defined in video_file, line 7
  • There is a live preview of the video, comment line 24 to avoid this
  • You can stop the process at any time pressing the Q letter
using System;
using OpenCvSharp;

var videoFile = "01.mp4";
System.IO.Directory.CreateDirectory("frames");

var capture = new VideoCapture(videoFile);
var window = new Window("El Bruno - OpenCVSharp Save Video Frame by Frame");
var image = new Mat();

var i = 0;
while (capture.IsOpened())
{
    capture.Read(image);
    if (image.Empty())
        break;

    i++;
    var imgNumber = i.ToString().PadLeft(8, '0');

    var frameImageFileName = $@"frames\image{imgNumber}.png";
    Cv2.ImWrite(frameImageFileName, image);

    window.ShowImage(image);
    if (Cv2.WaitKey(1) == 113) // Q
        break;
}

Console.WriteLine("Complete !");

Happy coding!

Greetings

El Bruno


#dotnet – Display a video file🎥 in Winform using #OpenCV and #net5

Buy Me A Coffee

Hi !

Super short post today, however is the base of the next series of posts around OpenCV and .Net 5. I already wrote on how to work with a webcam, and now it’s time to share a simple piece of code to show

How to open and process a video frame by frame

I’ve downloaded a “traffic cam” video from Youtube, and this is the output in a Winform.

Super easy ! And as usual, the source code

using System;
using System.Threading;
using System.Windows.Forms;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using Size = OpenCvSharp.Size;
namespace Demo13_WinFormVideoFromFile
{
public partial class Form1 : Form
{
private bool _run = false;
private VideoCapture _capture;
private Mat _image;
private Thread _cameraThread;
private string _videoFile = "4K camera example for Traffic Monitoring (Road).mp4";
private delegate void SafeCallDelegate(string text);
public Form1()
{
InitializeComponent();
Load += Form1_Load;
Closed += Form1_Closed;
}
private void Form1_Closed(object sender, EventArgs e)
{
_cameraThread.Interrupt();
_capture.Release();
}
private void btnStart_Click(object sender, EventArgs e)
{
_capture = new VideoCapture(_videoFile);
_run = true;
}
private void btnStop_Click(object sender, EventArgs e)
{
_run = false;
}
private void Form1_Load(object sender, EventArgs e)
{
_image = new Mat();
_cameraThread = new Thread(new ThreadStart(CaptureCameraCallback));
_cameraThread.Start();
}
private void CaptureCameraCallback()
{
while (true)
{
if (!_run) continue;
var startTime = DateTime.Now;
_capture.Read(_image);
if (_image.Empty()) return;
var imageRes = new Mat();
Cv2.Resize(_image, imageRes, new Size(320, 240));
var bmpWebCam = BitmapConverter.ToBitmap(imageRes);
pictureBoxWebCam.Image = bmpWebCam;
}
}
}
}

And the source video

Happy coding!

Greetings

El Bruno


References

#dotnet – Packaging my WinForm #OpenCV and #net5 app in a one-self contained file (Thanks @shanselman!)

Buy Me A Coffee

Hi !

A couple of days ago, Scott Hanselman posted about a super cool feature (see references):

… you can make a single EXE that will run on any Windows Machine in two commands

How to make a WinForms app with .NET 5 entirely from the command line and publish as one self-contained file

and I was wondering, how this would work with my Winform tests with OpenCV. So, I pick up my Face Recognition using DNN app and decided to give it a try.

When I just build my Face Recognition using DNN app, it creates an output with

  • 22 files
  • 9 folders

Of course, including the Caffe model and the proto file. And I know, I can remove some unnecessary files, this is just for reference.

opencv net5 winform app with all the included files

Back to Scott’s post, I decided to clean this and run the publish command

dotnet publish -r win-x64 /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true

And the output was amazing:

  • My application (exe) self-contained file
  • My ML Models, prototxt and caffe model
  • OpenCVSharp dependency for Windows
opencv net5 winform app self contained file

This is great ! But wait, there is still an option here to PACK everything, that’s mean add the parameter IncludeAllContentForSelfExtract=True

dotnet publish -r win-x64 /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true /p:IncludeAllContentForSelfExtract=True

And, it really packs everything. However, it does not work in my default code. OpenCVSharp load the models from a physical location, and using the IncludeNativeLibrariesForSelfExtract option, the caffe model and prototxt are embedded as resources.

_netPose = CvDnn.ReadNetFromCaffe(PoseProtoTxt, PoseCaffeModel);
_netPose.SetPreferableBackend(Net.Backend.OPENCV);

There should be a trick here, for sure. I’ll spend some time to figure out, how we can load models directly from a single package app file!

Happy coding!

Greetings

El Bruno


References