StronglyTyped.Generator
1.23.10401.11315
dotnet add package StronglyTyped.Generator --version 1.23.10401.11315
NuGet\Install-Package StronglyTyped.Generator -Version 1.23.10401.11315
<PackageReference Include="StronglyTyped.Generator" Version="1.23.10401.11315" />
paket add StronglyTyped.Generator --version 1.23.10401.11315
#r "nuget: StronglyTyped.Generator, 1.23.10401.11315"
// Install StronglyTyped.Generator as a Cake Addin
#addin nuget:?package=StronglyTyped.Generator&version=1.23.10401.11315
// Install StronglyTyped.Generator as a Cake Tool
#tool nuget:?package=StronglyTyped.Generator&version=1.23.10401.11315
Strongly Typed
What is it?
Strongly Typed is a library of interfaces and extensions that allow developers to strongly type simple primitive values.
Using strongly typed values eliminates certain classes of errors and potential bugs from code. You can't mix up two Guid
arguments to a method if they are of different types! You can also implement domain-specific functionality on types, or
allow conversions or other operations. This is the incremental source generator that generates the bulk of the strong
type.
What do I do with it?
This library should be used with StronglyTyped.Common, which defines the interfaces, attributes, and extension methods for working with strongly typed values. You create a "stub" implementation and add an attribute which tags it for the Source Generator's attention.
For example, the Generator will generate an Employee Id type from this stub:
[StrongGuid] public partial record struct EmployeeId;
Note that it must be partial
, the Source Generator will implement the rest.
The namespace will be preserved, as will any enclosing types (static
or non-static
), those must also be partial
,
like so:
namespace MyNamespace
{
public static partial class Employee
{
[StrongGuid] public partial record struct Id;
}
}
This will generate a strongly typed Guid
of type Id
nested in the Employee
static class, in the namespace MyNamespace
,
for a full type name of MyNamespace.Employee.Id
.
These types implement a TypeConverter
, so they will convert transparently to and from primitive types for, say, ASP .Net
model binding for action methods. They also serialize and deserialize to and from Json transparently using System.Text.Json
,
so if , say, your web client application uses javascript in AJAX it is not necessary to do any conversions. The serialization
and deserialization will take care of mapping the strong types to the correct primitive types.
But I want more control over my values!
These strong types use partial
methods to provide options for manipulating values and validating them. For example,
[StrongGuid]
public partial record struct HasAnOverriddenToString
{
static partial void _overrideToString(Guid value, ref string result)
{
result = $"Overridden {value}";
}
}
This will cause the HasAnOverriddenToString
's ToString() method to return Overridden 7240837c-757e-4c02-b592-28b7c24132c6
for a value that
contains the Guid
7240837c-757e-4c02-b592-28b7c24132c6
.
There are other partial
methods which can be implemented, depending on the wrapped primitive type. For example, the StrongGuid
types allow
overrides for the following:
/// <summary>
/// If implemented, the wrapped value will be preprocessed by this method before creation
/// Preprocessing runs before validation (if implemented)
/// </summary>
/// <param name="value">The value which is to be preprocessed</param>
static partial void _preprocess(ref global::System.Guid result);
/// <summary>
/// If implemented, the result of calling CompareTo on the wrapped value will be modified by this method
/// </summary>
/// <param name="result">The value which will be returned by CompareTo</param>
partial void _overrideEquals(AStrongGuid? obj, ref global::System.Boolean result);
/// <summary>
/// If implemented, the result of calling ToString on the wrapped value will be modified by this method
/// </summary>
/// <param name="result">The value which will be returned by ToString</param>
static partial void _overrideToString(global::System.Guid value, ref global::System.String result);
/// <summary>
/// If implemented, the result of calling CompareTo on the wrapped value will be modified by this method
/// </summary>
/// <param name="result">The value which will be returned by CompareTo</param>
partial void _overrideCompareTo(global::System.Object? obj, ref global::System.Int32 result);
/// <summary>
/// If implemented, this method will be used to check that the value is valid.
/// Validation runs after preprocessing (if implemented)
/// If errors contains any values validation will be considered to have failed.
/// (note that using the constructor, Create, or cast operators will not use this method)
/// </summary>
/// <param name="errors">A set of reasons why the value fails validation</param>
partial void _validate(ref global::System.Collections.Generic.HashSet<global::System.String> errors);
What is left to do?
Lots of other types. I have code for the following, which will be added as I find the time and energy to verify, write tests, and generally tidy up:
- StrongBool
- StrongByte
- StrongDecimal
- StrongDouble
- StrongFloat
- StrongHalf
- StrongInt
- StrongLong
- StrongSByte
- StrongShort
- StrongString
- StrongUInt
- StrongULong
- StrongUShort
The following are on my to-do list:
- StrongDateTime
- StrongDateOnly
- StrongTimeOnly
- Newtonsoft Json.Net support
I also have some extension methods for Entity Framework that map these types to the database as though they were the primitive types they wrap, but that will come in a separate package.
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 | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. 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.0
- No dependencies.
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 |
---|
Initial release.