Show / Hide Table of Contents

Base Class Library Enhancements

Randomization

Related class: RandomExtensions

Extension methods for random data generation extends both classes Random and RandomNumberGenerator.

Random blittable values

Provides a way to generate random values of arbitrary types:

using DotNext;
using System;
using System.Security.Cryptography;

var rand = new Random();
Int128 password = rand.Next<Int128>();
password = RandomNumberGenerator.Next<Int128>();

Random boolean generation

Provides a way to generate boolean value with the given probability

using DotNext;

var rand = new Random();
var b = rand.NextBoolean(0.3D); //0.3 is a probability of TRUE value

The same extension method is provided for class RandomNumberGenerator.

String extensions

Related class: StringExtensions, Span

Reverse string

Extension method Reverse allows to reverse string characters and returns a new string:

using DotNext;

var str = "abc".Reverse(); //str is "cba"

Trim by length

Extension method TrimLength limits the length of string or span:

using DotNext;

var str = "abc".TrimLength(2);  //str is "ab"
str = "abc".TrimLength(4);  //str is "abc"

Span<int> array = new int[] { 10, 20, 30 };
array = array.TrimLength(2);    //array is { 10, 20 }

Delegates

Related classes: DelegateHelpers.

Change type of delegate

Different types of delegates can refer to the same method. For instance, Func<string, string> represents the same signature as Converter<string, string>. It means that the delegate instance can be converted into another delegate type if signature matches.

using DotNext;

Func<string, int> lengthOf = str => str.Length;
Converter<string, int> lengthOf2 = lengthOf.ChangeType<Converter<string, int>>();

Predefined delegates

Cached delegate instances for mostly used delegate types: Predicate<T>, Func<T, TResult> and Action.

using DotNext;

Func<int, int> identity = Func<int>.Identity; //identity delegate which returns input argument without any changes
Predicate<bool> truePredicate = Predicate<bool>.Constant(true); // predicate which always returns true
Predicate<bool> falsePredicate = Predicate<bool>.Constant(false); //predicate which always returns false
Predicate<string> nullCheck = Predicate<string>.IsNull; //predicate checking whether the input argument is null
Predicate<string> notNullCheck = Predicate<string>.IsNotNull; //predicate checking whether the input argument is not null

Logical operators for Predicate

Extension methods implementation logical operators for Predicate delegate instances:

using DotNext;

Predicate<string> predicate = str => str.Length == 0;
predicate = !predicate;
predicate = predicate & new Predicate<string>(str => str.Length > 2);
predicate = predicate | new Predicate<string>(str => str.Length % 2 == 0);
predicate = predicate ^ new Predicate<string>(Predicate<string>.IsNull);

Delegate Factories

C# 9 introduces typed function pointers. However, conversion between regular delegates and function pointers is not supported. DelegateHelpers offers factory methods allowing creation of delegate instances from function pointers. These factory methods support implicit capturing of the first argument as well:

using DotNext;

static int GetHashCode(string s)
{
}

delegate*<string, int> hashCode = &GetHashCode;
Func<string, int> openDelegate = Func<string, int>.FromPointer(hashCode);
Func<int> closedDelegate = Func<int>.FromPointer<string, int>(hashCode, "Hello, world!");

Binding

The delegate instance is a combination of the implicit first argument and the target method. Binding is a way to associate the implicit first argument with the delegate. This concept is used widely in JavaScript. .NEXT exposes this functionality through Bind extension method or << operator. The binding can be chained.

Func<int, int, int> sum = (x, y) => x + y;
Func<int, int> f = sum << 42; // bind 42 to x
f.Invoke(12); // returns 42 + 12

Func<int> f2 = sum << 42 << 12; // bind 42 to x and 12 to y, and produce Func<int>
f.Invoke(); // returns 42 + 12

sum << 42 can be replaced with sum.Bind(42) call that has the same effect.

Range check

Checks whether the given value is in specific range.

using DotNext;

var b = 10.IsBetween(5.Enclosed, 11.Enclosed); //b == true
b = 10.IsBetween(0.Disclosed, 4.Disclosed); //b == false

Equality check

Related classes: BasicExtensions.

Extension method IsOneOf allows to check whether the value is equal to one of the given values.

using DotNext;

var b = 42.IsOneOf(0, 5, 42, 3); //b == true

b = "a".IsOneOf("b", "c", "d"); //b == false

Equality check

BitwiseEquals extension method performs bitwise equality between two regions of memory referenced by the arrays. Element type of these arrays should be of unmanaged value type, e.g. int, long, System.Guid.

var array2 = new int[] { 1, 2, 3 };
array2.BitwiseEquals(new [] {1, 2, 4});    //false

Timestamp

Timestamp value type can be used as allocation-free alternative to Stopwatch when you need to measure time intervals.

using DotNext.Diagnostics;
using System;

var timestamp = new Timestamp();
//long-running operation
Console.WriteLine(timestamp.Elapsed);

Elapsed property returning value of TimeSpan type which indicates the difference between timestamp and the current point in time.

This type should not be used as a unique identifier of some point in time. The created time stamp may identify the time since the start of the process, OS, user session or whatever else.

Dynamic Task Result

In .NET it is not possible to obtain a result from task if its result type is not known at compile-time. It can be useful if you are writing proxy or SOAP Middleware using ASP.NET Core and task type is not known for your code. .NEXT provides two ways of doing that:

  1. Synchronous method GetResult which is located in Synchronization class
  2. Asynchronous method AsDynamic which is located in Conversion class.

All you need is to have instance of non-generic Task class because all types tasks derive from it.

Under the hood, .NEXT uses Dynamic Language Runtime feature in combination with high-speed optimizations.

The following example demonstrates this approach:

using DotNext.Threading.Tasks;
using System.Threading.Tasks;

//assume that t is of unknown Task<T> type
Task t = Task.FromResult("Hello, world!");

//obtain result synchronously
Result<dynamic> result = t.GetResult(CancellationToken.None);

//obtain result asynchronously
dynamic result = await t.AsDynamic();

Ref-like structs in generic context

LocalReference<T> is a simple wrapper by-ref struct that allows to encapsulate the managed pointer to any arbitrary type, including other by-ref structs. This type allows to pass typed managed pointers as generic arguments, as well as holding the managed pointer to by-ref struct within another by-ref struct, which is currently restricted by C# compiler.

int i = 42;
LocalReference<int> reference = new(ref i);

Under the hood, LocalReference<T> type is the same as ref T type. ReadOnlyLocalReference<T> type is the same as ref readonly T type.

  • Edit this page
☀
☾
In this article
Back to top
Supported by the .NET Foundation
☀
☾