RSCG – UnitGenerator
Generating classes instead of value objects( e.g. int)
This is how you can use UnitGenerator .
The code that you start with is
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="UnitGenerator" Version="1.5.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>
The code that you will use is
// See https://aka.ms/new-console-template for more information
using StronglyDemo;
Person p = new();
//p.SetBirthDate(1970, 4, 16);
p.SetBirthDate(new YearId(1970) , new MonthId(4),new DayId( 16));
Console.WriteLine(p.BirthDate);
using UnitGenerator;
namespace StronglyDemo;
[UnitOf(typeof(int))]
public partial struct YearId { }
[UnitOf(typeof(int))]
public partial struct MonthId { }
[UnitOf(typeof(int))]
public partial struct DayId { }
internal class Person
{
public DateTime BirthDate { get; internal set; }
public void SetBirthDate(YearId yearId,MonthId monthId,DayId dayId)
{
BirthDate = new DateTime(yearId.AsPrimitive(), monthId.AsPrimitive(), dayId.AsPrimitive());
}
}
The code that is generated is
// <auto-generated>
// THIS (.cs) FILE IS GENERATED BY UnitGenerator. DO NOT CHANGE IT.
// </auto-generated>
#pragma warning disable CS8669
using System;
using System.Globalization;
#if NET7_0_OR_GREATER
using System.Numerics;
#endif
namespace StronglyDemo
{
[System.ComponentModel.TypeConverter(typeof(DayIdTypeConverter))]
readonly partial struct DayId
: IEquatable<DayId>
#if NET7_0_OR_GREATER
, IEqualityOperators<DayId, DayId, bool>
#endif
{
readonly int value;
public int AsPrimitive() => value;
public DayId(int value)
{
this.value = value;
}
public static explicit operator int(DayId value)
{
return value.value;
}
public static explicit operator DayId(int value)
{
return new DayId(value);
}
public bool Equals(DayId other)
{
return value.Equals(other.value);
}
public override bool Equals(object obj)
{
if (obj == null) return false;
var t = obj.GetType();
if (t == typeof(DayId))
{
return Equals((DayId)obj);
}
if (t == typeof(int))
{
return value.Equals((int)obj);
}
return value.Equals(obj);
}
public static bool operator ==(DayId x, DayId y)
{
return x.value.Equals(y.value);
}
public static bool operator !=(DayId x, DayId y)
{
return !x.value.Equals(y.value);
}
public override int GetHashCode()
{
return value.GetHashCode();
}
public override string ToString() => value.ToString();
// Default
private class DayIdTypeConverter : System.ComponentModel.TypeConverter
{
private static readonly Type WrapperType = typeof(DayId);
private static readonly Type ValueType = typeof(int);
public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == WrapperType || sourceType == ValueType)
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == WrapperType || destinationType == ValueType)
{
return true;
}
return base.CanConvertTo(context, destinationType);
}
public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value != null)
{
var t = value.GetType();
if (t == typeof(DayId))
{
return (DayId)value;
}
if (t == typeof(int))
{
return new DayId((int)value);
}
}
return base.ConvertFrom(context, culture, value);
}
public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
if (value is DayId wrappedValue)
{
if (destinationType == WrapperType)
{
return wrappedValue;
}
if (destinationType == ValueType)
{
return wrappedValue.AsPrimitive();
}
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
}
}
// <auto-generated>
// THIS (.cs) FILE IS GENERATED BY UnitGenerator. DO NOT CHANGE IT.
// </auto-generated>
#pragma warning disable CS8669
using System;
using System.Globalization;
#if NET7_0_OR_GREATER
using System.Numerics;
#endif
namespace StronglyDemo
{
[System.ComponentModel.TypeConverter(typeof(MonthIdTypeConverter))]
readonly partial struct MonthId
: IEquatable<MonthId>
#if NET7_0_OR_GREATER
, IEqualityOperators<MonthId, MonthId, bool>
#endif
{
readonly int value;
public int AsPrimitive() => value;
public MonthId(int value)
{
this.value = value;
}
public static explicit operator int(MonthId value)
{
return value.value;
}
public static explicit operator MonthId(int value)
{
return new MonthId(value);
}
public bool Equals(MonthId other)
{
return value.Equals(other.value);
}
public override bool Equals(object obj)
{
if (obj == null) return false;
var t = obj.GetType();
if (t == typeof(MonthId))
{
return Equals((MonthId)obj);
}
if (t == typeof(int))
{
return value.Equals((int)obj);
}
return value.Equals(obj);
}
public static bool operator ==(MonthId x, MonthId y)
{
return x.value.Equals(y.value);
}
public static bool operator !=(MonthId x, MonthId y)
{
return !x.value.Equals(y.value);
}
public override int GetHashCode()
{
return value.GetHashCode();
}
public override string ToString() => value.ToString();
// Default
private class MonthIdTypeConverter : System.ComponentModel.TypeConverter
{
private static readonly Type WrapperType = typeof(MonthId);
private static readonly Type ValueType = typeof(int);
public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == WrapperType || sourceType == ValueType)
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == WrapperType || destinationType == ValueType)
{
return true;
}
return base.CanConvertTo(context, destinationType);
}
public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value != null)
{
var t = value.GetType();
if (t == typeof(MonthId))
{
return (MonthId)value;
}
if (t == typeof(int))
{
return new MonthId((int)value);
}
}
return base.ConvertFrom(context, culture, value);
}
public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
if (value is MonthId wrappedValue)
{
if (destinationType == WrapperType)
{
return wrappedValue;
}
if (destinationType == ValueType)
{
return wrappedValue.AsPrimitive();
}
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
}
}
// <auto-generated>
// THIS (.cs) FILE IS GENERATED BY UnitGenerator. DO NOT CHANGE IT.
// </auto-generated>
#pragma warning disable CS8669
using System;
using System.Globalization;
#if NET7_0_OR_GREATER
using System.Numerics;
#endif
namespace StronglyDemo
{
[System.ComponentModel.TypeConverter(typeof(YearIdTypeConverter))]
readonly partial struct YearId
: IEquatable<YearId>
#if NET7_0_OR_GREATER
, IEqualityOperators<YearId, YearId, bool>
#endif
{
readonly int value;
public int AsPrimitive() => value;
public YearId(int value)
{
this.value = value;
}
public static explicit operator int(YearId value)
{
return value.value;
}
public static explicit operator YearId(int value)
{
return new YearId(value);
}
public bool Equals(YearId other)
{
return value.Equals(other.value);
}
public override bool Equals(object obj)
{
if (obj == null) return false;
var t = obj.GetType();
if (t == typeof(YearId))
{
return Equals((YearId)obj);
}
if (t == typeof(int))
{
return value.Equals((int)obj);
}
return value.Equals(obj);
}
public static bool operator ==(YearId x, YearId y)
{
return x.value.Equals(y.value);
}
public static bool operator !=(YearId x, YearId y)
{
return !x.value.Equals(y.value);
}
public override int GetHashCode()
{
return value.GetHashCode();
}
public override string ToString() => value.ToString();
// Default
private class YearIdTypeConverter : System.ComponentModel.TypeConverter
{
private static readonly Type WrapperType = typeof(YearId);
private static readonly Type ValueType = typeof(int);
public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == WrapperType || sourceType == ValueType)
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == WrapperType || destinationType == ValueType)
{
return true;
}
return base.CanConvertTo(context, destinationType);
}
public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value != null)
{
var t = value.GetType();
if (t == typeof(YearId))
{
return (YearId)value;
}
if (t == typeof(int))
{
return new YearId((int)value);
}
}
return base.ConvertFrom(context, culture, value);
}
public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
if (value is YearId wrappedValue)
{
if (destinationType == WrapperType)
{
return wrappedValue;
}
if (destinationType == ValueType)
{
return wrappedValue.AsPrimitive();
}
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
}
}
// <auto-generated>
// THIS (.cs) FILE IS GENERATED BY UnitGenerator. DO NOT CHANGE IT.
// </auto-generated>
#pragma warning disable CS8669
#pragma warning disable CS8625
using System;
#if NET7_0_OR_GREATER
using System.Numerics;
#endif
namespace UnitGenerator
{
[AttributeUsage(AttributeTargets.Struct, AllowMultiple = false)]
internal class UnitOfAttribute : Attribute
{
public Type Type { get; }
public UnitGenerateOptions Options { get; }
public UnitArithmeticOperators ArithmeticOperators { get; set; } = UnitArithmeticOperators.All;
public string ToStringFormat { get; set; }
public UnitOfAttribute(Type type, UnitGenerateOptions options = UnitGenerateOptions.None)
{
this.Type = type;
this.Options = options;
}
}
[Flags]
internal enum UnitGenerateOptions
{
None = 0,
ImplicitOperator = 1,
ParseMethod = 1 << 1,
MinMaxMethod = 1 << 2,
ArithmeticOperator = 1 << 3,
ValueArithmeticOperator = 1 << 4,
Comparable = 1 << 5,
Validate = 1 << 6,
JsonConverter = 1 << 7,
MessagePackFormatter = 1 << 8,
DapperTypeHandler = 1 << 9,
EntityFrameworkValueConverter = 1 << 10,
WithoutComparisonOperator = 1 << 11,
JsonConverterDictionaryKeySupport = 1 << 12,
Normalize = 1 << 13,
}
[Flags]
internal enum UnitArithmeticOperators
{
All = Addition | Subtraction | Multiply | Division | Increment | Decrement,
Addition = 1,
Subtraction = 1 << 1,
Multiply = 1 << 2,
Division = 1 << 3,
Increment = 1 << 4,
Decrement = 1 << 5,
}
}
Code and pdf at
https://ignatandrei.github.io/RSCG_Examples/v2/docs/UnitGenerator