The following example demonstrates how to generate a random integer.
Random random = new Random();
int num = random.Next();
Call the Next()
method multiple times to get the multiple random numbers, as shown below.
Random random = new Random();
for (int i = 0; i < 4; i++)
{
Console.WriteLine(random.Next());
}
Use the Next(int)
method overload to generate a random integer that is less than the specified maximum value.
The following example generates the positive random numbers that are less than 10.
Random random = new Random();
for (int i = 0; i < 4; i++)
{
Console.WriteLine(random.Next(10)); // returns random integers < 10
}
Use the Next(int min, int max)
overload method to get a random integer that is within a specified range.
Random random = new Random();
for(int i = 0; i < 4; i++)
{
Console.WriteLine(random.Next(10, 20)); // returns random integers >= 10 and < 19
}
The Random
class uses the seed value as a starting value for the pseudo-random number generation algorithm. By default, the Random
class uses the system clock to generate its seed value so that each instance of the Random
class can generate different random numbers.
Two different instances of the Random
class having the same seed value will generate the same random numbers, as shown below.
Random random1 = new Random(10); // seed value 10
for (int i = 0; i < 4; i++){
Console.WriteLine(random1.Next());
}
Random random2 = new Random(10); // seed value 10, the same as in the first
for (int i = 0; i < 4; i++){
Console.WriteLine(random2.Next());
}
Use the following methods of the Random class to generate random numbers.
Source: Generate Random Numbers in C# (tutorialsteacher.com)
We can also use the \
escape character to store the string He said "Hi"
inside a string variable in C#. We would have to write a \
before each double quote like He said \"Hi\"
. The following code example shows us how we can escape double quotes with the \
escape character in C#.
string msg = "He said \"Hi\""; Console.WriteLine(msg);
Output:
He said "Hi"
We saved the string msg
with the value He said "Hi"
by using the \
escape character in C#.
C# Switch Statements
Use the switch statement to select one of many code blocks to be executed.
switch(expression) { case a: // code block break; case b: // code block break; default: // code block break; }
This is how it works:
switch
expression is evaluated oncecase
break
and default
keywords will be described later in this chapterDesign patterns are reusable solutions to common problems in software design and factory design pattern is one of the common design patterns.
The Factory method is a creational design pattern that provides an interface for creating objects without specifying their concrete classes. It defines a method that we can use to create an object instead of using its constructor. The important thing is that the subclasses can override this method and create objects of different types.
Resources
Context
The code block
public async void OnGet(int id)
{
Book = await _db.Books.SingleOrDefaultAsync(x => x.Id == id);
return Page();
}
Issue
This code will generate the following exception
System.ObjectDisposedException: 'Cannot access a disposed context instance. A common cause of this error is disposing a context instance that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling 'Dispose' on the context instance, or wrapping it in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
Reason
This exception will be thrown because the method return type is async void
. In general, when using async void
is bad, because:
Solution
So return async Task
instead of async void
from the method as follows:
public async Task OnGet(int id)
{
Book = await _db.Books.SingleOrDefaultAsync(x => x.Id == id);
return Page();
}
Lambda expression(s => s.Name == "lastname")
s
: input parameter=>
: lambda operator tokens.Name == "lastname"
: expression to be evaluatedC# defines the following character escape sequences:
Mutex also helps us to ensure that our code is thread-safe. That means when we run our code in a multi-threaded environment then we don’t end up with inconsistent results.
public static class MutexSample
{
public static void Exeute()
{
for (int i = 0; i < 5; i++)
{
Thread doWorkThread = new Thread(new ParameterizedThreadStart(doWork));
doWorkThread.Start(i);
}
Console.ReadLine();
}
//Mutex(mutual exclusion) is very similar to lock/Monitor. The difference is that it can work across multiple processes.
//Make mutex.
private static Mutex mutex = new Mutex();
private static void doWork(object threadNumber)
{
try
{
//The code will stop executing here and wait until the lock is released by the previous thread.
mutex.WaitOne();
Console.WriteLine("Thread " + threadNumber.ToString() + " has started.");
//Simulate doing time consuming work.
Thread.Sleep(1500);
Console.WriteLine("Thread " + threadNumber.ToString() + " is done.");
}
finally
{
//Realesase the lock so other threads can now get access.
mutex.ReleaseMutex();
}
}
}
Semaphore is mainly used in scenarios where we have a limited number of resources and we have to limit the number of threads that can use it. The semaphore class lets you limit the number of threads accessing a critical section.
Semaphores are Int32 variables stored in an operating system's resources. When we initialize the semaphore object, we initialize it with a number. This number limits the threads that can enter the critical section.
For using a semaphore in C#, you just need to instantiate an instance of a Semaphore object.
public static class SemaphoreSample
{
public static void Execute()
{
for (int i = 0; i < 5; i++)
{
Thread doWorkThread = new Thread(new ParameterizedThreadStart(doWork));
doWorkThread.Start(i);
}
Console.ReadLine();
}
//A semaphore is very similar to lock/Monitor. The difference is that it can allow for a specified amount of threads to work with the same resources at the same time.
//Make a semaphore that allows for up to two threads to work with the same resource.
private static Semaphore semaphore = new Semaphore(1, 1); //Semaphore(initial thread count, max thread count)
private static void doWork(object threadNumber)
{
try
{
//The code will stop executing here and wait until the lock is released by the previous thread.
semaphore.WaitOne();
Console.WriteLine("Thread " + threadNumber.ToString() + " has started.");
//Simulate doing time consuming work.
Thread.Sleep(1500);
Console.WriteLine("Thread " + threadNumber.ToString() + " is done.");
}
finally
{
//Realesase the lock so other threads can now get access.
semaphore.Release();
}
}
}
Information about Mutex
Information about Semaphore
Being a reference to the method, a delegate in C# works like a function pointer in C and C++. As compared to a function pointer, a delegate in C# is objected-oriented, secured, and type-safe.
Delegate => action, as lambda
Resources
Convert any JSON object to a C# class online with the Json2CSharp Toolkit.
See at Convert JSON to C# Classes Online - Json2CSharp Toolkit
JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easily read and written by humans and parsed and generated by machines. The application/json
is the official Internet media type for JSON. The JSON filename extension is .json.
The System.Text.Json
namespace provides high-performance, low-allocating, and standards-compliant tools to work with JSON. The classes allow us to serialize objects into JSON text and deserialize JSON text to objects. The UTF-8 support is built-in.
The JsonDocument.Parse
parses a stream as UTF-8-encoded data representing a single JSON value into a JsonDocument
. The stream is read to completion.
using System.Text.Json;
string data = @" [ {""name"": ""Krish Jackon"", ""phoneNumber"": ""123456""},
{""name"": ""Marc Moore"", ""phoneNumber"": ""654321""} ]";
using JsonDocument doc = JsonDocument.Parse(data);
JsonElement root = doc.RootElement;
The JsonSerializer.Serialize
converts the value of a specified type into a JSON string.
using System.Text.Json;
var user = new User("Krish Jackon", "female", new MyDate(1985, 03, 30));
var json = JsonSerializer.Serialize(user);
Console.WriteLine(json);
The JsonSerializer.Deserialize
parses the text representing a single JSON value into an instance of a specified type.
using System.Text.Json;
string json = @"{""Name"":""Krish Jackon"", ""Gender"":""female"",
""DateOfBirth"":{""year"":1985,""month"":03,""day"":30}}";
var user = JsonSerializer.Deserialize<User>(json);
Resources to deserialize to dynamic object
ImageSharp - A cross-platform library for the processing of image files; written in C#
Compared to System.Drawing
ImageSharp has been able to develop something much more flexible, easier to code against, and much, much less prone to memory leaks. Gone are system-wide process-locks; ImageSharp images are thread-safe and fully supported in web environments.
using (Image<Rgba32> image = Image.Load("foo.jpg"))
{
image.Mutate(x => x
.Resize(image.Width / 2, image.Height / 2)
.Grayscale());
image.Save("bar.jpg"); // Automatic encoder selected based on extension.
}
ImageSharp Documentation
Some Discussions
The C# Retry Pattern is a coding strategy that enhances fault tolerance by automatically reattempting failed operations. Employing this pattern involves defining retry logic, such as delays between attempts, to improve the robustness and reliability of code handling transient errors.
Further Resources
This example in C# illustrates an implementation of the Retry pattern. The purpose of this method is to repeatedly attempt to execute a piece of code (referred to as the "main logic") until either the operation is successful or a specified number of retries has been reached.
public async Task RetryAsync()
{
int retryCount = 3;
int currentRetry = 0;
for (;;)
{
try
{
// main logic here
break; // Return or break.
}
catch (Exception ex)
{
currentRetry++;
if (currentRetry > this.retryCount) throw;
}
await Task.Delay(TimeSpan.FromSeconds(5));
}
}
Breakdown of the code:
for (;;)
)
for
loop without a condition, meaning it will continue indefinitely until explicitly broken out of.currentRetry++;
: Increments the currentRetry
counter each time an exception is caught.currentRetry
) has exceeded the maximum allowed retries (retryCount
).
throw;
, propagating it further.All types and type members have an accessibility level. The accessibility level controls whether they can be used from other code in your assembly or other assemblies.
Caller's location | public |
protected internal |
protected |
internal |
private protected |
private |
---|---|---|---|---|---|---|
Within the class | ✔️️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
Derived class (same assembly) | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ❌ |
Non-derived class (same assembly) | ✔️ | ✔️ | ❌ | ✔️ | ❌ | ❌ |
Derived class (different assembly) | ✔️ | ✔️ | ✔️ | ❌ | ❌ | ❌ |
Non-derived class (different assembly) | ✔️ | ❌ | ❌ | ❌ | ❌ | ❌ |
See more at Access Modifiers - C# Programming Guide - C# | Microsoft Learn
When dealing with nested lists in C# and needing to flatten them, LINQ's SelectMany
method comes in handy. Here's a simple example:
var orders = new List<Order>();
var distinctOrderLines = orders.SelectMany(order => order.OrderLines).Distinct();
This code snippet flattens the orders
list containing lists of OrderLines into a single sequence of distinct OrderLines
.
For more information and examples, you can refer to these resources
The ObsoleteAttribute in .NET Framework is used to mark types or members as obsolete, indicating they will be removed in future versions. This helps prevent breaking existing code that relies on these elements. Here's an example:
using System;
public class MyClass
{
[Obsolete("Method1 is deprecated, please use Method2 instead.", true)]
public void Method1()
{
// Deprecated code here
}
public void Method2()
{
// New code here
}
}
In this example, calling Method1() will raise a compilation error due to the true parameter, enforcing the use of Method2() instead.
Adittional resources:
In C#, to compare two strings ignoring case sensitivity, you can use the string.Equals method with StringComparison.OrdinalIgnoreCase as shown below:
string val = "aStringValue";
bool isEqual = string.Equals(val, "astringvalue", StringComparison.OrdinalIgnoreCase);
This code snippet compares the val
string with "astringvalue" regardless of case sensitivity and returns a boolean indicating if they are equal.
For more details and discussions about comparing strings in C# while ignoring case, you can refer to this Stack Overflow thread: Comparing two strings ignoring case in C#.
To deserialize JSON into a dynamic object in C# using System.Json, follow these steps:
Here's an example code snippet:
using System.Json;
string jsonString = "{\"name\":\"John\",\"age\":30}";
JsonValue jsonValue = JsonValue.Parse(jsonString);
dynamic dynamicObj = jsonValue.ToDynamic();
Console.WriteLine($"Name: {dynamicObj.name}, Age: {dynamicObj.age}");
For more advanced JSON deserialization scenarios in C#, using libraries like Json.NET (Newtonsoft.Json) is recommended.
Some helpful links
The provided source code defines a simple DependencyProvider class responsible for managing dependencies using .NET Core's built-in dependency injection system. The class includes a method to retrieve required services based on their interfaces.
public static class DependencyProvider
{
private static IServiceProvider Provider()
{
var services = new ServicesCollection();
services.AddSingleton<IClient, Client>();
return services.BuildServiceProvider();
}
public static T GetRequiredService<T>() where T : notnull
{
var provider = Provider();
return provider.GetRequiredService<T>();
}
}
To use this DependencyProvider, you can retrieve instances of required services as shown below:
readonly IClient _client = DependencyProvider.GetRequiredService<IClient>();
To add IConfiguration
to the service collection, you can use the IServiceCollection
interface. First, create a ServiceCollection
instance, then use the AddSingleton
method to add IConfiguration
, passing in your configuration object _config
.
IConfigurationBuilder builder = new ConfigurationBuilder()
.SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
.AddJsonFile("appsettings.json");
IConfiguration configuration = builder.Build();
IServiceCollection services = new ServiceCollection();
services.AddSingleton<IConfiguration>(configuration);
This setup is particularly useful for scenarios like unit testing background services, as discussed in this Stack Overflow thread: Unit testing a .NET Core background service.
To filter out nullable strings and obtain only non-null strings, you can use LINQ Where
method along with a null check. Here's an example:
IEnumerable<string?> nullableStrings //
List<string> nonNullStringsList = nullableStrings
.Where(s => s != null) // Filter out null values
.Select(s => s!) // Convert nullable strings to non-nullable
.ToList(); // Convert IEnumerable to List
Where
to filter out null values and Select
to convert nullable strings to non-nullable strings (string!
indicates a non-nullable reference type in C# 8.0 and later).ToList()
to convert the filtered enumerable to a List<string>
.C# is a strongly-typed language. It means we must declare the type of a variable that indicates the kind of values it is going to store, such as integer, float, decimal, text,
Additional reading at Data types in C# (tutorialsteacher.com)
In C#, a string is a series of characters that is used to represent text. It can be a character, a word or a long passage surrounded with the double quotes ". The following are string literals.
// String Literal Examples
"S"
"String"
"This is a string."
C# includes specialized classes that store series of values or objects are called collections.
There are two types of collections available in C#: non-generic collections and generic collections.
The System.Collections
namespace contains the non-generic collection types and System.Collections.Generic
namespace includes generic collection types.
Additional reading at C# Generic & Non-generic Collections (tutorialsteacher.com)
Problem Statement: Extracting extended file properties, such as the Media Created Date, is necessary for certain applications. Utilizing the Microsoft.WindowsAPICodePack.Shell namespace facilitates this task efficiently.
Approach: Utilize the ShellObject class from the WindowsAPICodePack.Shell namespace to access extended file properties. Specifically, retrieve the Media Created Date using the System.Media.DateEncoded property.
using Microsoft.WindowsAPICodePack.Shell;
ShellObject shell = ShellObject.FromParsingName(path);
var mediaCreatedDate = shell.Properties.System.Media.DateEncoded;
Explanation: This code utilizes the ShellObject class to access extended file properties. It fetches the Media Created Date of a file specified by its path using the System.Media.DateEncoded property, providing crucial metadata for various applications.
Further resources
Convert any JSON object to a C# class online. Check out these online tools.
How to protect shared resources and serialize the processing using Mutex and Semaphore.
This set shows some ways of doing thread synchronization in C#.
C# provides the Random class to generate random numbers based on the seed value.