RSCG – Vogen
| name | Vogen |
| nuget | https://www.nuget.org/packages/Vogen/ |
| link | https://dunnhq.com/posts/2021/primitive-obsession/ |
| author | Steve Dunn |
Transform values( e.g. int) into classes
If you know what are ValueObject,that is one solution
This is how you can use Vogen .
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>
<ItemGroup>
<PackageReference Include="Vogen" Version="3.0.16" />
</ItemGroup>
<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
</Project>
The code that you will use is
// See https://aka.ms/new-console-template for more information using DemoVogen; Console.WriteLine("Hello,World!"); var p = PersonId.From(123); var p1 = PersonId.From(123); var p2 =(PersonId) 123; Console.WriteLine(p == 123); Console.WriteLine(p == p1); Console.WriteLine(p == p2);
// See https://aka.ms/new-console-template for more information
using Vogen;
namespace DemoVogen;
[ValueObject<int>]
public partial struct PersonId
{
}
The code that is generated is
// ------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a source generator named Vogen (https://github.com/SteveDunn/Vogen)
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------
// Suppress warnings about [Obsolete] member usage in generated code.
#pragma warning disable CS0618
// Suppress warnings for 'Override methods on comparable types'.
#pragma warning disable CA1036
// Suppress Error MA0097 : A class that implements IComparable<T> or IComparable should override comparison operators
#pragma warning disable MA0097
// Suppress warning for 'The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. Auto-generated code requires an explicit '#nullable' directive in source.'
// The generator copies signatures from the BCL,e.g. for `TryParse`,and some of those have nullable annotations.
#pragma warning disable CS8669
// Suppress warnings about CS1591: Missing XML comment for publicly visible type or member 'Type_or_Member'
#pragma warning disable CS1591
using Vogen;
namespace DemoVogen
{
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Vogen","3.0.0.0")]
[global::System.Text.Json.Serialization.JsonConverter(typeof(PersonIdSystemTextJsonConverter))]
[global::System.ComponentModel.TypeConverter(typeof(PersonIdTypeConverter))]
[global::System.Diagnostics.DebuggerTypeProxyAttribute(typeof(PersonIdDebugView))]
[global::System.Diagnostics.DebuggerDisplayAttribute("Underlying type: System.Int32,Value = { _value }")]
public partial struct PersonId : global::System.IEquatable<PersonId>,global::System.IEquatable<System.Int32>,global::System.IComparable<PersonId>,global::System.IComparable
{
#if DEBUG
private readonly global::System.Diagnostics.StackTrace _stackTrace = null;
#endif
private readonly global::System.Boolean _isInitialized;
private readonly System.Int32 _value;
/// <summary>
/// Gets the underlying <see cref="System.Int32" /> value if set,otherwise a <see cref="ValueObjectValidationException" /> is thrown.
/// </summary>
public readonly System.Int32 Value
{
[global::System.Diagnostics.DebuggerStepThroughAttribute]
get
{
EnsureInitialized();
return _value;
}
}
[global::System.Diagnostics.DebuggerStepThroughAttribute]
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public PersonId()
{
#if DEBUG
_stackTrace = new global::System.Diagnostics.StackTrace();
#endif
_isInitialized = false;
_value = default;
}
[global::System.Diagnostics.DebuggerStepThroughAttribute]
private PersonId(System.Int32 value)
{
_value = value;
_isInitialized = true;
}
/// <summary>
/// Builds an instance from the provided underlying type.
/// </summary>
/// <param name="value">The underlying type.</param>
/// <returns>An instance of this type.</returns>
public static PersonId From(System.Int32 value)
{
PersonId instance = new PersonId(value);
return instance;
}
public static explicit operator PersonId(System.Int32 value) => From(value);
public static explicit operator System.Int32(PersonId value) => value.Value;
// only called internally when something has been deserialized into
// its primitive type.
private static PersonId Deserialize(System.Int32 value)
{
return new PersonId(value);
}
public readonly global::System.Boolean Equals(PersonId other)
{
// It's possible to create uninitialized instances via converters such as EfCore (HasDefaultValue),which call Equals.
// We treat anything uninitialized as not equal to anything,even other uninitialized instances of this type.
if(!_isInitialized || !other._isInitialized) return false;
return global::System.Collections.Generic.EqualityComparer<System.Int32>.Default.Equals(Value,other.Value);
}
public readonly global::System.Boolean Equals(System.Int32 primitive) => Value.Equals(primitive);
public readonly override global::System.Boolean Equals(global::System.Object obj)
{
return obj is PersonId && Equals((PersonId) obj);
}
public static global::System.Boolean operator ==(PersonId left,PersonId right) => Equals(left,right);
public static global::System.Boolean operator !=(PersonId left,PersonId right) => !(left == right);
public static global::System.Boolean operator ==(PersonId left,System.Int32 right) => Equals(left.Value,right);
public static global::System.Boolean operator !=(PersonId left,System.Int32 right) => !Equals(left.Value,right);
public static global::System.Boolean operator ==(System.Int32 left,PersonId right) => Equals(left,right.Value);
public static global::System.Boolean operator !=(System.Int32 left,PersonId right) => !Equals(left,right.Value);
public int CompareTo(PersonId other) => Value.CompareTo(other.Value);
public int CompareTo(object other) {
if(other == null) return 1;
if(other is PersonId x) return CompareTo(x);
throw new global::System.ArgumentException("Cannot compare to object as it is not of type PersonId",nameof(other));
}
/// <inheritdoc cref="int.TryParse(System.ReadOnlySpan{char},System.Globalization.NumberStyles,System.IFormatProvider?,out int)"/>
/// <summary>
/// </summary>
/// <returns>
/// The value created via the <see cref="From"/> method.
/// </returns>
/// <exception cref="ValueObjectValidationException">Thrown when the value can be parsed,but is not valid.</exception>
public static global::System.Boolean TryParse(global::System.ReadOnlySpan<char> s,global::System.Globalization.NumberStyles style,global::System.IFormatProvider provider,
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
out PersonId result) {
if(System.Int32.TryParse(s,style,provider,out var r)) {
result = From(r);
return true;
}
result = default;
return false;
}
/// <inheritdoc cref="int.TryParse(System.ReadOnlySpan{char},System.IFormatProvider?,out int)"/>
/// <summary>
/// </summary>
/// <returns>
/// The value created via the <see cref="From"/> method.
/// </returns>
/// <exception cref="ValueObjectValidationException">Thrown when the value can be parsed,but is not valid.</exception>
public static global::System.Boolean TryParse(global::System.ReadOnlySpan<char> s,global::System.IFormatProvider provider,
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
out PersonId result) {
if(System.Int32.TryParse(s,provider,out var r)) {
result = From(r);
return true;
}
result = default;
return false;
}
/// <inheritdoc cref="int.TryParse(System.ReadOnlySpan{char},out int)"/>
/// <summary>
/// </summary>
/// <returns>
/// The value created via the <see cref="From"/> method.
/// </returns>
/// <exception cref="ValueObjectValidationException">Thrown when the value can be parsed,but is not valid.</exception>
public static global::System.Boolean TryParse(global::System.ReadOnlySpan<char> s,
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
out PersonId result) {
if(System.Int32.TryParse(s,out var r)) {
result = From(r);
return true;
}
result = default;
return false;
}
/// <inheritdoc cref="int.TryParse(string?,System.Globalization.NumberStyles,System.IFormatProvider?,out int)"/>
/// <summary>
/// </summary>
/// <returns>
/// The value created via the <see cref="From"/> method.
/// </returns>
/// <exception cref="ValueObjectValidationException">Thrown when the value can be parsed,but is not valid.</exception>
public static global::System.Boolean TryParse(string s,global::System.Globalization.NumberStyles style,global::System.IFormatProvider provider,
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
out PersonId result) {
if(System.Int32.TryParse(s,style,provider,out var r)) {
result = From(r);
return true;
}
result = default;
return false;
}
/// <inheritdoc cref="int.TryParse(string?,System.IFormatProvider?,out int)"/>
/// <summary>
/// </summary>
/// <returns>
/// The value created via the <see cref="From"/> method.
/// </returns>
/// <exception cref="ValueObjectValidationException">Thrown when the value can be parsed,but is not valid.</exception>
public static global::System.Boolean TryParse(string s,global::System.IFormatProvider provider,
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
out PersonId result) {
if(System.Int32.TryParse(s,provider,out var r)) {
result = From(r);
return true;
}
result = default;
return false;
}
/// <inheritdoc cref="int.TryParse(string?,out int)"/>
/// <summary>
/// </summary>
/// <returns>
/// The value created via the <see cref="From"/> method.
/// </returns>
/// <exception cref="ValueObjectValidationException">Thrown when the value can be parsed,but is not valid.</exception>
public static global::System.Boolean TryParse(string s,
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
out PersonId result) {
if(System.Int32.TryParse(s,out var r)) {
result = From(r);
return true;
}
result = default;
return false;
}
public readonly override global::System.Int32 GetHashCode() => global::System.Collections.Generic.EqualityComparer<System.Int32>.Default.GetHashCode(_value);
/// <summary>Returns the string representation of the underlying type</summary>
/// <inheritdoc cref="System.Int32.ToString()" />
public readonly override global::System.String ToString() =>_isInitialized ? Value.ToString() : "[UNINITIALIZED]";
private readonly void EnsureInitialized()
{
if (!_isInitialized)
{
#if DEBUG
global::System.String message = "Use of uninitialized Value Object at: " + _stackTrace ?? "";
#else
global::System.String message = "Use of uninitialized Value Object.";
#endif
throw new global::Vogen.ValueObjectValidationException(message);
}
}
class PersonIdSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter<PersonId>
{
public override PersonId Read(ref global::System.Text.Json.Utf8JsonReader reader,global::System.Type typeToConvert,global::System.Text.Json.JsonSerializerOptions options)
{
return PersonId.Deserialize(reader.GetInt32());
}
public override void Write(System.Text.Json.Utf8JsonWriter writer,PersonId value,global::System.Text.Json.JsonSerializerOptions options)
{
writer.WriteNumberValue(value.Value);
}
#if NET6_0_OR_GREATER
public override PersonId ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader,global::System.Type typeToConvert,global::System.Text.Json.JsonSerializerOptions options)
{
return PersonId.Deserialize(global::System.Int32.Parse(reader.GetString(),global::System.Globalization.NumberStyles.Any,global::System.Globalization.CultureInfo.InvariantCulture));
}
public override void WriteAsPropertyName(System.Text.Json.Utf8JsonWriter writer,PersonId value,global::System.Text.Json.JsonSerializerOptions options)
{
writer.WritePropertyName(value.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture));
}
#endif
}
class PersonIdTypeConverter : global::System.ComponentModel.TypeConverter
{
public override global::System.Boolean CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext context,global::System.Type sourceType)
{
return sourceType == typeof(global::System.Int32) || sourceType == typeof(global::System.String) || base.CanConvertFrom(context,sourceType);
}
public override global::System.Object ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext context,global::System.Globalization.CultureInfo culture,global::System.Object value)
{
return value switch
{
global::System.Int32 intValue => PersonId.Deserialize(intValue),
global::System.String stringValue when !global::System.String.IsNullOrEmpty(stringValue) && global::System.Int32.TryParse(stringValue,out var result) => PersonId.Deserialize(result),
_ => base.ConvertFrom(context,culture,value),
};
}
public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext context,global::System.Type sourceType)
{
return sourceType == typeof(global::System.Int32) || sourceType == typeof(global::System.String) || base.CanConvertTo(context,sourceType);
}
public override object ConvertTo(global::System.ComponentModel.ITypeDescriptorContext context,global::System.Globalization.CultureInfo culture,global::System.Object value,global::System.Type destinationType)
{
if (value is PersonId idValue)
{
if (destinationType == typeof(global::System.Int32))
{
return idValue.Value;
}
if (destinationType == typeof(global::System.String))
{
return idValue.Value.ToString();
}
}
return base.ConvertTo(context,culture,value,destinationType);
}
}
internal sealed class PersonIdDebugView
{
private readonly PersonId _t;
PersonIdDebugView(PersonId t)
{
_t = t;
}
public global::System.Boolean IsInitialized => _t._isInitialized;
public global::System.String UnderlyingType => "System.Int32";
public global::System.String Value => _t._isInitialized ? _t._value.ToString() : "[not initialized]" ;
#if DEBUG
public global::System.String CreatedWith => _t._stackTrace?.ToString() ?? "the From method";
#endif
public global::System.String Conversions => @"Default";
}
}
}
Code and pdf at
https://ignatandrei.github.io/RSCG_Examples/v2/docs/Vogen
Leave a Reply