TryAtSoftware.Randomizer
1.0.4
Prefix Reserved
See the version list below for details.
dotnet add package TryAtSoftware.Randomizer --version 1.0.4
NuGet\Install-Package TryAtSoftware.Randomizer -Version 1.0.4
<PackageReference Include="TryAtSoftware.Randomizer" Version="1.0.4" />
paket add TryAtSoftware.Randomizer --version 1.0.4
#r "nuget: TryAtSoftware.Randomizer, 1.0.4"
// Install TryAtSoftware.Randomizer as a Cake Addin #addin nuget:?package=TryAtSoftware.Randomizer&version=1.0.4 // Install TryAtSoftware.Randomizer as a Cake Tool #tool nuget:?package=TryAtSoftware.Randomizer&version=1.0.4
About the project
TryAtSoftware.Randomizer
is a library that should simplify the process of random values generation.
We offer a set of methods and components that can be used to generate random values of different types. They are reusable and can be applied to every projects of yours.
About us
Try At Software
is a software development company based in Bulgaria. We are mainly using dotnet
technologies (C#
, ASP.NET Core
, Entity Framework Core
, etc.) and our main idea is to provide a set of tools that can simplify the majority of work a developer does on a daily basis.
Getting started
Installing the package
Before creating any randomizers, you need to install the package.
The simplest way to do this is to either use the NuGet package manager
, or the dotnet CLI
.
Using the NuGet package manager
console within Visual Studio, you can install the package using the following command:
Install-Package TryAtSoftware.Randomizer
Or using the dotnet CLI
from a terminal window:
dotnet add package TryAtSoftware.Randomizer
Creating your first randomizer
To define a randomizer, you need to create a class that implements the IRandomizer<T>
interface, where T
is the type of information this component should be responsible for randomizing.
For example, imagine that you want to create a randomizer that generates a random DateTime
instance in the future.
You would need the following class:
using System;
using TryAtSoftware.Randomizer.Core.Helpers;
using TryAtSoftware.Randomizer.Core.Interfaces;
public class DateTimeRandomizer : IRandomizer<DateTime>
{
private readonly DateTime _instantiationTime = DateTime.Now;
public DateTime PrepareRandomValue()
{
// We want to generate a random DateTime instance that is a few minutes ahead of our current time.
var randomOffsetInMinutes = RandomizationHelper.RandomInteger(15, 60);
return this._instantiationTime.AddMinutes(randomOffsetInMinutes);
}
}
Then you can use this randomizer as follows:
var dateTimeRandomizer = new DateTimeRandomizer();
for (int i = 0; i < 5; i++)
{
var randomDateTime = dateTimeRandomizer.PrepareRandomValue();
Console.WriteLine(randomDateTime);
}
If you run this code, you will see that the output is a few random DateTime
instances.
You may notice that the output sometimes may contain a value more than once.
This is because the strength
of our randomizer is not great.
If we analyze it more deeply, we can see that it can generate only 45 different values by design.
We will discuss various mechanisms to increase the strength
of our randomizers in some of the next sections.
Randomizing complex types
As you saw in the previous chapter, writing standard randomizers for simple types is easy - you just implement a single method and that's it.
Randomizing complex types is not a more complex operation. We have provided you whit a base class that you can use to implement your own complex randomizers.
It is called ComplexRandomizer<T>
where T
is the complex type it should be responsible for randomizing.
Let's start with a basic example! For simplicity, we will work with this model:
using System;
public class Person
{
public Guid Id { get; set; }
public string Name { get; set; }
public bool IsEmployed { get; set; }
public int Age { get; set; }
public DateTimeOffset EventDate { get; set; }
}
Our complex randomizer will look like this:
using TryAtSoftware.Randomizer.Core;
using TryAtSoftware.Randomizer.Core.Primitives;
public class PersonRandomizer : ComplexRandomizer<Person>
{
public PersonRandomizer()
{
this.AddRandomizationRule(p => p.Id, new GuidRandomizer());
this.AddRandomizationRule(p => p.Name, new StringRandomizer());
this.AddRandomizationRule(p => p.Age, new NumberRandomizer());
this.AddRandomizationRule(p => p.IsEmployed, new BooleanRandomizer());
this.AddRandomizationRule(p => p.EventDate, new DateTimeOffsetRandomizer());
}
}
Let's examine this complex randomizer!
We can see that it can be used to define a specific randomizer for each publicly exposed member of the Person
type.
And actually this is the main idea of our library. This way we can reuse already defined randomizers for different types.
We can combine them to create complex randomizers that can generate random instances of any type. Isn't that great?!
If we want to examine the complex randomization process more deeply, we can see that it is contained of two phases that we will describe in the next sections.
Instance building phase
The IInstanceBuilder<T>
is a component responsible for instantiating the complex type.
By default, a GeneralInstanceBuilder<T>
will be used if none is specified.
This is the recommended option of instance building as it is implemented to find the most suitable constructor and invoke it (so you do not have to write any additional code).
Furthermore, it tracks down the used parameters so the randomization rules defining them will not be used during the next phase of the complex randomization process.
However, if you want to implement one by yourself, you have a few options:
- You can implement the
IInstanceBuilder<Person>
interface and define some custom instantiation logic. If you chose this option, you are in full control of the instantiation process.
using TryAtSoftware.Randomizer.Core;
using TryAtSoftware.Randomizer.Core.Interfaces;
public class PersonInstanceBuilder : IInstanceBuilder<Person>
{
public IInstanceBuildingResult<Person> PrepareNewInstance(IInstanceBuildingArguments arguments)
{
// You can use the provided instance building arguments to customize the instance.
// Note that if you do so, the returned instance building result may need some changes.
var person = new Person();
return new InstanceBuildingResult<Person>(person);
}
}
- You may inherit the
SimpleInstanceBuilder<T>
class and implement thePrepareNewInstance
method. This option should be used for really simple instance building that does not require any additional parameters being provided to the constructor. It is most suitable for complex types that have publicly exposed non-read-only members.
using TryAtSoftware.Randomizer.Core;
public class PersonInstanceBuilder : SimpleInstanceBuilder<Person>
{
protected override Person PrepareNewInstance() => new Person();
}
Value setting phase
In this phase the SetValue
method for the value setter of each registered randomization rule will be invoked.
The order will be preserved - the value setter of a given randomization rule will be invoked before the value setter of a randomization rule that is registered after the given.
Best practices and recommendations
- We do not recommend using
complex randomizers
with abstract classes or interfaces. While it is possible to make such a setup work, there may be some intricacies along the way. TheAddRandomizationRule
andOverrideRandomizationRule
methods are publicly exposed so extension methods can be extracted (or even inheritance will get the job done for some simple cases). Another idea that is especially useful when dealing with many derived types that have behavioral but not structural differences, is to make thecomplex randomizer
generic.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.1 is compatible. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- TryAtSoftware.Extensions.Reflection (>= 1.1.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
2.0.2 | 178 | 3/13/2024 |
2.0.2-alpha.1 | 346 | 8/15/2023 |
2.0.1 | 443 | 6/14/2023 |
1.0.4 | 184 | 6/13/2023 |
1.0.4-alpha.4 | 1,515 | 1/31/2023 |
1.0.4-alpha.3 | 99 | 1/25/2023 |
1.0.4-alpha.2 | 100 | 1/14/2023 |
1.0.4-alpha.1 | 104 | 1/11/2023 |
1.0.3 | 709 | 3/6/2022 |
1.0.3-alpha.4 | 147 | 2/3/2022 |
1.0.3-alpha.3 | 130 | 2/3/2022 |
1.0.3-alpha.2 | 128 | 2/3/2022 |
1.0.3-alpha.1 | 126 | 2/3/2022 |
1.0.2 | 735 | 6/11/2021 |
1.0.1 | 316 | 6/11/2021 |