From 2e3b4fc3e7d094e52990be6e8429459c05e1b27e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=B6rcs=C3=B6k=20Bal=C3=A1zs=20R=C3=B3bert?= Date: Tue, 27 Aug 2024 20:23:54 +0200 Subject: [PATCH] Blogposts, better front page. --- content/_index.md | 4 +- content/entity-framework-02.md | 16 ++++++ content/extension-methods.md | 16 ++++++ content/generic-delegate-types.md | 87 +++++++++++++++++++++++++++++ content/null-checking-in-c-sharp.md | 48 ++++++++++++++++ 5 files changed, 169 insertions(+), 2 deletions(-) create mode 100644 content/entity-framework-02.md create mode 100644 content/extension-methods.md create mode 100644 content/generic-delegate-types.md create mode 100644 content/null-checking-in-c-sharp.md diff --git a/content/_index.md b/content/_index.md index 070872d..2dec26d 100644 --- a/content/_index.md +++ b/content/_index.md @@ -1,5 +1,5 @@ +++ -paginate_by = 3 -sort_by = "update_date" +paginate_by = 6 +sort_by = "date" template = "index.html" +++ diff --git a/content/entity-framework-02.md b/content/entity-framework-02.md new file mode 100644 index 0000000..233060f --- /dev/null +++ b/content/entity-framework-02.md @@ -0,0 +1,16 @@ ++++ +title = "Primer in databases: Components of databases" +date = 2024-08-12 +updated = 2024-08-12 +description = "" +[taxonomies] +tags = ["database","SQL","DBMS",".NET"] ++++ + + + +## Types of data in databases + +## SQL or noSQL? + +## Components of a DBMS diff --git a/content/extension-methods.md b/content/extension-methods.md new file mode 100644 index 0000000..30f6657 --- /dev/null +++ b/content/extension-methods.md @@ -0,0 +1,16 @@ ++++ +title = "Extension methods in C#" +date = 2024-08-27 +updated = 2024-08-27 +description = "" +[taxonomies] +tags = ["C#","microsoft",".NET", "extension methods"] ++++ + +We already looked at a post explaining events and delegates that libraries might want to provide us with functionality to decide what happens at certain points in our application, especially if these libraries are GUI libraries. This was event driven programming. + +However, not all use cases are meant to be done via event driver programming and there definitely are cases where we would want to extend the functionality of a library, without recompiling it, either because we can't (no source code) or don't want to (too complicated). Traditionally you could just write the relevant wrappers to it, but C# provides advanced syntactic sugar to call specific kind of methods as if they were the part of the library. + +In this case C# provides extension methods. It is a similar concept to the decorator design pattern, but that is a rather dynamic way of extending the functionality via common interfaces, but extension methods are completely compile time structures and have specific rules about them. + +***To be continued...*** diff --git a/content/generic-delegate-types.md b/content/generic-delegate-types.md new file mode 100644 index 0000000..41fed1d --- /dev/null +++ b/content/generic-delegate-types.md @@ -0,0 +1,87 @@ ++++ +title = "Generic delegate types in .NET" +date = 2024-08-25 +updated = 2024-08-25 +description = "" +[taxonomies] +tags = ["C#","microsoft",".NET", "generic", "delegate"] ++++ + +***This post is a WIP, but I posted it because it already contains some cool information***😁 + +Recently I have written a blogpost about the `add` and `remove` keywords. We had to dvelve into multiple concept, including delegates. For a quick refresher: delegates are similar to function pointers from the world of C/C++. They are object for storing information about the signature of a method, making it possible to to later define or call a method on an object matching their signature. This is useful for defining for instance what kind of reactions can be provided for events. + +Generics are used to introduce the concept of type parameters. The primary use of them is to be able to define fully functional classes and methods that defer the specification of one or more type parameters until that given class or method is used somewhere else in the code. Generic classes are meant for reusability, type safety and efficiency. When compilation happens, generic type parameters are replaced by the caller's argument(s). (Parameter: the symbol used to mark the symbol value in a signature. Argument: the actual value of the symbol. This is true for any function, even in math.) + +One of the most common use cases of generics is in containers, which we will have a lengthy look at in a later blogpost. The reason for it is that containers are meant to be used on any type of data, and their operations are clearly defined to be independent from the data they store. (Of course for custom solutions, this might not hold true.) You can find many in the `System.Collections.Generic` namespace in .NET. + +A cool feature of generics is that they provide a way to make constraints regarding the type parameters. The reason why this is not a limitation, is that when creating a generic, you can introduce operations on the generic parameters, which are supported by the constrained type. You can also make a constraint where you define what something is not, allowing you to make operations, otherwise not available. By default all generic parameters unless constrained otherwise are `System.Object` type, meaning that you can only do operations, which are supported by that. It is a very broad topic, so I would recommend taking a look at [the programming guide](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters) to see all the possible ways you can make them and it can get especially messy, because some versions of C# might not allow constraints, which are otherwise allowed in the CLR. + +Generics are similar to templates in C++. Emphasis on similar, because it is clearly defined that they do not wish to implement the same feature set or syntax that templates do in C++. The very core idea of templates in C++ is that it is a tool to programmatically define our program. In other words, it is a way to write down the rules, which produce program code, so we program the compiler to produce code. It is completely compile-time. This is why C++ template programming is also called metaprogramming, because we work on a level higher, than our program code will. + +Briefly, I would like to show what is *not* provided in generics, but is in templates: + +- Type parameters can not have default types. + +There are 5 main groups of delegates. They can be categorized according to return and functionality: + +There is the concept of variance in generics that is needed to fully understand and distinguish between generic delegate types. +Variance allows the programmer to define and use more derived types (covariance) or more generic types (contravariance). There are 2 contextual keywords associated with this: `out` is for covariance and `in` is for contravariance. Both keywords apply to a generic type so they must be used like `` or ``, where `T` is the generic type parameter. + +Let's see how covariance, the `out` keyword works: + +Let's say I have a program for managing a pet shop. As a base class, I define animals, but because I also work with dogs and they have their own needs, I define a class for dogs: + +```c# +public class Animal {} +public class Dog : Animal {} +``` + +Now, we probably have to order some animals if we want to sell them. As a general employee responsibility, for any type of animal this can be defined, so we define this as an interface. We also specify this for dogs, so we create a `DogOrder` class, which implements the `IOrder` interface for the `Dog` class, thus we give it the type parameter `IOrder`. + +```c# +public interface IOrder +{ + T Order(); +} +public class DogOrder : IOrder +{ + public Dog Order() + { + return new Dog(); + } +} +``` + +Now because we defined `T` as `out T` in `IOrder`, it means that as `T` is the return type, the returned object can be assigned to the parent class, and this by definition is the meaning of covariance: + +```c# +class Program +{ + static void Main() + { + IOrder dogOrder = new DogOrder(); + IOrder animalOrder = dogOrder; // Covariance allows this assignment + + Animal animal = animalOrder.GetItem(); + } +} +``` + +In the context of the example this might mean something like that the pet shop employee may fill out a form for a dog order, but then copy all the info to a generic pet shop order and make the order, because the supplier will know how to handle it. + +Due to the generalization feature of covariance, it might only be used as return types of methods. + +### Action-type generic delegates + +We have already seen these in my blogpost about `add` and `remove`. + +```c# +public delegate void Action(); +public delegate void Action(T1 arg1, T2 arg2); +public delegate void Action(T1 arg1, T2 arg2, T3 arg3); +... +public delegate void ACtion (T1 arg1, ..., T16 arg16); +``` + +These are all void type delegates, which support from no input up 16 any type of object input. They are mostly meant for event handling, but the `EventHandler` is preferred to it in that context. I would use it for any purely side-effect producing function, which is not strictly an event. Also, I think that for logically coherent parameters or more than a few, like 3, I would encapsulate them as their own object and pass that as an argument. diff --git a/content/null-checking-in-c-sharp.md b/content/null-checking-in-c-sharp.md new file mode 100644 index 0000000..2269a83 --- /dev/null +++ b/content/null-checking-in-c-sharp.md @@ -0,0 +1,48 @@ ++++ +title = "Checking for null values in .NET" +date = 2024-08-27 +updated = 2024-08-27 +description = "" +[taxonomies] +tags = ["C#","microsoft",".NET", "null checking", "type safety", "nameof operator"] ++++ + +By the design of C# reference types can have the value of `null`. This is perfectly normal and developers are supposed to use it as a feature. The problem stems from most developers not taking care of it, when working with references (which is on the most part of the job). As when we call on a member of a `null` object reference, it causes `NullReferenceException`, which is probably not managed on the application level causing a crash. + +While the most common causes of crash in invalid memory access in C and C++, the main cause of crashes is probably `null` dereference. +To do this, the easiest way is to check the object reference if it is equal to `null` via the `==` equality operator. For `String` types, I recommend using the `IsNullOrEmpty()` method, as empty string probably mean the same as `null` in the application context. + +Since C# 6.0 you can use the unary and ternary null propagation operators to simplify checking for `null`. +Let's say you have the object `nullableObject`, which can have a `null` value. If you write `nullableObject?.myValue` or `nullableObject?.myMethod()`, it conditionally only calls the part after the dot, if the object was not `null`. + +You can also use `??` like `nullableObject?.myValue ?? otherValue` (and similarly for method calls) which produces either the left hand side `myValue` if `nullableObject` is not `null` or `otherValue` if it is (or the method calls' return value). + +On this note, it is a good practice, if you want to explicitly handle if a reference was `null` and output an exception about it, I would use the `nameof(myObject)`, in an exception call, for instance: + +```c# +void myMethod(string s) +{ + if (s == null) + { + throw new ArgumentNullException(s); + } +} +``` + +This is unreliable, because there is no guarantee, that the exception message will correctly resolve for the variable name, especially if `s` was `null`. + +Also, you could pass `"s"` as the exception message, but the problem with that is that if the actual parameter name is changed, it might be that the exception message is not modified by accident, leading to confusion, but at the very least unneeded maintenance costs. + +If you however do: + +```c# +void myMethod(string s) +{ + if (s == null) + { + throw new ArgumentNullException(nameof(s)); + } +} +``` + +The compiler will always resolve to the actual parameter name, making debugging easier.