Skip to content

Commit

Permalink
Showing 39 changed files with 10,097 additions and 34 deletions.
8 changes: 4 additions & 4 deletions docs/site/Writerside/topics/how-to/Testing.md
Original file line number Diff line number Diff line change
@@ -14,9 +14,9 @@ So the tests are in two solutions:

* In the **main solution**, there are [snapshot tests](https://github.com/VerifyTests/Verify) which create **in-memory projects** that exercise the generators using different versions of the .NET Framework.
These are slow to run because they use many different permutations of features and dozens of variations of configuration/primitive-type/C#-type/accessibility-type/converters, for example:
* does it correctly generate a record struct with instances and normalization and a type converter and a Dapper serializer
* does it correctly generate a class with no converters, no validation, and no serialization
* does it correctly generate a readonly struct with a LinqToDb converter
* does it correctly generate a record struct with instances and normalization and a type converter and a Dapper serializer?
* does it correctly generate a class with no converters, no validation, and no serialization?
* does it correctly generate a readonly struct with a LinqToDb converter?
* etc. etc.

(all tests run for each supported framework)
@@ -30,7 +30,7 @@ The snapshot tests in the IDE run in about 5 minutes. In the CI build, we set a
These tests are much quicker to run.
They verify the behavior
of created Value Objects, such as:
* [Normalization](https://github.com/SteveDunn/Vogen/wiki/Normalization)
* [Normalization](NormalizationHowTo.md "How to use normalization")
* Equality
* Hashing
* ToString
15 changes: 8 additions & 7 deletions docs/site/Writerside/topics/reference/Configuration.md
Original file line number Diff line number Diff line change
@@ -8,22 +8,23 @@ This topic is incomplete and is currently being improved.
Each Value Object can have its own *optional* configuration. Configuration includes:

* The underlying type
* Any 'conversions' (Dapper, System.Text.Json, Newtonsoft.Json, etc.) - see [the Integrations page](https://github.com/SteveDunn/Vogen/wiki/Integration) in the wiki for more information
* Any 'conversions' (Dapper, System.Text.Json, Newtonsoft.Json, etc.) - see Integrations in the wiki for more information
* The type of the exception that is thrown when validation fails

If any of those above are not specified, then global configuration is inferred. It looks like this:

```c#
[assembly: VogenDefaults(underlyingType: typeof(int), conversions: Conversions.Default, throws: typeof(ValueObjectValidationException))]
[assembly: VogenDefaults(
underlyingType: typeof(int),
conversions: Conversions.Default,
throws: typeof(ValueObjectValidationException))]
```

Those again are optional. If they're not specified, then they are defaulted to:

* Underlying type = `typeof(int)`
* Conversions = `Conversions.Default` (`TypeConverter` and `System.Text.Json`)
* Validation exception type = `typeof(ValueObjectValidationException)`
* Conversions = `Conversions.Default` which is `TypeConverter` and `System.Text.Json`
* Validation exception type = which is `ValueObjectValidationException`

There are several code analysis warnings for invalid configuration, including:
Several code analysis warnings exist for invalid configuration, including:

* when you specify an exception that does not derive from `System.Exception`
* when your exception does not have one public constructor that takes an int
33 changes: 21 additions & 12 deletions docs/site/Writerside/topics/reference/FAQ.md
Original file line number Diff line number Diff line change
@@ -43,8 +43,7 @@ correct.
## How do I identify types that are generated by Vogen?
_I'd like to be able to identify types that are generated by Vogen so that I can integrate them in things like EFCore._

**A: ** You can use this information on [this page](How-to-identify-a-type-that-is-generated-by-Vogen.md)

This is described in [this how-to page](How-to-identify-a-type-that-is-generated-by-Vogen.md)

### What versions of .NET are supported?

@@ -325,20 +324,14 @@ Yes, add NormalizeInput method, e.g.
```c#
private static string NormalizeInput(string input) => input.Trim();
```
See [wiki](https://github.com/SteveDunn/Vogen/wiki/Normalization) for more information.
See [the how-to page](NormalizationHowTo.md) for more information.


### Can I create custom Value Object attributes with my own defaults?

Yes, but (at the moment) it requires that you put your defaults in your attribute's constructor—not in the call to
the base class' constructor (see [this comment](https://github.com/SteveDunn/Vogen/pull/321#issuecomment-1399324832)).

```c#
public class CustomValueObjectAttribute : ValueObjectAttribute<long>
{
// This attribute will default to having both the default conversions and EF Core type conversions
public CustomValueObjectAttribute(Conversions conversions = Conversions.Default | Conversions.EfCoreValueConverter) { }
}
No. It used to be possible, but it impacts the performance of Vogen.
A much better way is
to use [type alias feature C# 12](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-12.0/using-alias-types).
```
NOTE: *custom attributes must extend a ValueObjectAttribute class; you cannot layer custom attributes on top of each other*
@@ -470,3 +463,19 @@ The BoxId type will now be serialized as a `string` in all messages and grpc cal
for other applications from C#, proto files will include the `Surrogate` type as the type.

_thank you to [@DomasM](https://github.com/DomasM) for this information_.

### Can I have a factory method for value objects that wrap GUIDs?

Yes, use the `Customizations.AddFactoryMethodForGuids` in the global config attribute, e.g.

```c#
[assembly: VogenDefaults(
customizations: Customizations.AddFactoryMethodForGuids)]

[ValueObject<Guid>]
public partial {{type}} CustomerId { }

...

var newCustomerId = CustomerId.FromNewGuid();
```
13 changes: 9 additions & 4 deletions src/Vogen.SharedTypes/Customizations.cs
Original file line number Diff line number Diff line change
@@ -3,8 +3,8 @@
namespace Vogen;

/// <summary>
/// Customization flags. For things like treating doubles as strings
/// during [de]serialization (for compatibility with JavaScript).
/// Customization flags. For simple binary choices.
/// More complex configuration options are specified as parameters in the <see cref="VogenDefaultsAttribute"/>.
/// </summary>
[Flags]
public enum Customizations
@@ -17,10 +17,15 @@ public enum Customizations
None = 0,

/// <summary>
/// When [de]serializing an underlying primitive that wold normally be written as a number in System.Text.Json,
/// When [de]serializing an underlying primitive that would normally be written as a number in System.Text.Json,
/// instead, treat the underlying primitive as a culture invariant string. This gets around the issue of
/// JavaScript losing precision on very large numbers. See <see href="https://github.com/SteveDunn/Vogen/issues/165"/>
/// for more information.
/// </summary>
TreatNumberAsStringInSystemTextJson = 1 << 0
TreatNumberAsStringInSystemTextJson = 1 << 0,

/// <summary>
/// For GUIDs, add a `FromNewGuid()` factory method, which is just `public static MyVo FromNewGuid() => From(Guid.NewGuid());`
/// </summary>
AddFactoryMethodForGuids = 1 << 1
}
2 changes: 1 addition & 1 deletion src/Vogen/Generators/ClassGenerator.cs
Original file line number Diff line number Diff line change
@@ -99,7 +99,7 @@ public string BuildClass(VoWorkItem item, TypeDeclarationSyntax tds)
public static global::System.Boolean operator ==({itemUnderlyingType} left, {className} right) => Equals(left, right.Value);
public static global::System.Boolean operator !=({itemUnderlyingType} left, {className} right) => !Equals(left, right.Value);
{GenerateCastingOperators.Generate(item,tds)}
{GenerateCastingOperators.Generate(item,tds)}{Util.GenerateGuidFactoryMethodIfRequired(item, tds)}
{GenerateComparableCode.GenerateIComparableImplementationIfNeeded(item, tds)}
{GenerateCodeForTryParse.GenerateAnyHoistedTryParseMethods(item)}{GenerateCodeForParse.GenerateAnyHoistedParseMethods(item)}
2 changes: 1 addition & 1 deletion src/Vogen/Generators/RecordClassGenerator.cs
Original file line number Diff line number Diff line change
@@ -106,7 +106,7 @@ public string BuildClass(VoWorkItem item, TypeDeclarationSyntax tds)
public static global::System.Boolean operator ==({itemUnderlyingType} left, {className} right) => Equals(left, right.Value);
public static global::System.Boolean operator !=({itemUnderlyingType} left, {className} right) => !Equals(left, right.Value);
{GenerateCastingOperators.Generate(item,tds)}
{GenerateCastingOperators.Generate(item,tds)}{Util.GenerateGuidFactoryMethodIfRequired(item, tds)}
{GenerateComparableCode.GenerateIComparableImplementationIfNeeded(item, tds)}
{GenerateCodeForTryParse.GenerateAnyHoistedTryParseMethods(item)}{GenerateCodeForParse.GenerateAnyHoistedParseMethods(item)}
2 changes: 1 addition & 1 deletion src/Vogen/Generators/RecordStructGenerator.cs
Original file line number Diff line number Diff line change
@@ -87,7 +87,7 @@ public readonly {itemUnderlyingType} Value
return instance;
}}
{GenerateEqualsAndHashCodes.GenerateStringComparersIfNeeded(item, tds)}
{GenerateCastingOperators.Generate(item,tds)}
{GenerateCastingOperators.Generate(item,tds)}{Util.GenerateGuidFactoryMethodIfRequired(item, tds)}
// only called internally when something has been deserialized into
// its primitive type.
private static {structName} Deserialize({itemUnderlyingType} value)
2 changes: 1 addition & 1 deletion src/Vogen/Generators/StructGenerator.cs
Original file line number Diff line number Diff line change
@@ -77,7 +77,7 @@ public readonly {itemUnderlyingType} Value
}}
{GenerateEqualsAndHashCodes.GenerateStringComparersIfNeeded(item, tds)}
{GenerateCastingOperators.Generate(item,tds)}
{GenerateCastingOperators.Generate(item,tds)}{Util.GenerateGuidFactoryMethodIfRequired(item, tds)}
// only called internally when something has been deserialized into
// its primitive type.
private static {structName} Deserialize({itemUnderlyingType} value)
10 changes: 10 additions & 0 deletions src/Vogen/Util.cs
Original file line number Diff line number Diff line change
@@ -223,6 +223,16 @@ public static string GenerateToStringReadOnly(VoWorkItem item) =>
$@"/// <summary>Returns the string representation of the underlying type</summary>
/// <inheritdoc cref=""{item.UnderlyingTypeFullName}.ToString()"" />
public readonly override global::System.String ToString() =>_isInitialized ? Value.ToString() : ""[UNINITIALIZED]"";";

public static string GenerateGuidFactoryMethodIfRequired(VoWorkItem item, TypeDeclarationSyntax tds)
{
if (item.UnderlyingTypeFullName == "System.Guid" && item.Customizations.HasFlag(Customizations.AddFactoryMethodForGuids))
{
return $"public static {item.VoTypeName} FromNewGuid() {{ return From(global::System.Guid.NewGuid()); }}";
}

return string.Empty;
}
}

public static class DebugGeneration
28 changes: 25 additions & 3 deletions tests/SnapshotTests/GeneralStuff/GeneralTests.cs
Original file line number Diff line number Diff line change
@@ -8,6 +8,31 @@ namespace SnapshotTests.GeneralStuff;
[UsesVerify]
public class GeneralTests
{
[Theory]
[InlineData("struct")]
[InlineData("class")]
[InlineData("record struct")]
[InlineData("record class")]
public async Task Can_specify_a_factory_method_for_wrappers_for_guids(string type)
{
var source = $$"""
using System;
using Vogen;
[assembly: VogenDefaults(customizations: Customizations.AddFactoryMethodForGuids)]
[ValueObject<Guid>]
public partial {{type}} MyVo { }
""";

await new SnapshotRunner<ValueObjectGenerator>()
.WithSource(source)
.CustomizeSettings(s => s.UseFileName(TestHelper.ShortenForFilename(type)))
.RunOnAllFrameworks();
}

[Fact]
public async Task ServiceStackDotTextConversion_generates_static_constructor_for_strings()
{
@@ -21,7 +46,6 @@ public partial struct MyVo { }
static Task RunTest(string source) =>
new SnapshotRunner<ValueObjectGenerator>()
.WithSource(source)
//.WithPackage(new NuGetPackage("ServiceStack.Text", "8.2.2", "lib/net8.0" ))
.RunOn(TargetFramework.Net8_0);
}

@@ -56,7 +80,6 @@ public partial struct MyVo { }
static Task RunTest(string source) =>
new SnapshotRunner<ValueObjectGenerator>()
.WithSource(source)
// .WithPackage(new NuGetPackage("ServiceStack.Text", "8.2.2", "lib/net8.0" ))
.RunOn(TargetFramework.Net8_0);
}

@@ -74,7 +97,6 @@ public partial struct MyVo { }
static Task RunTest(string source) =>
new SnapshotRunner<ValueObjectGenerator>()
.WithSource(source)
// .WithPackage(new NuGetPackage("ServiceStack.Text", "8.2.2", "lib/net8.0" ))
.RunOn(TargetFramework.Net8_0);
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,339 @@
// ------------------------------------------------------------------------------
// <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;


[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Vogen", "1.0.0.0")]
[global::System.Text.Json.Serialization.JsonConverter(typeof(MyVoSystemTextJsonConverter))]
[global::System.ComponentModel.TypeConverter(typeof(MyVoTypeConverter))]

[global::System.Diagnostics.DebuggerTypeProxyAttribute(typeof(MyVoDebugView))]
[global::System.Diagnostics.DebuggerDisplayAttribute("Underlying type: System.Guid, Value = { _value }")]
public partial struct MyVo : global::System.IEquatable<MyVo>, global::System.IEquatable<System.Guid>, global::System.IComparable<MyVo>, global::System.IComparable
{
#if DEBUG
private readonly global::System.Diagnostics.StackTrace _stackTrace = null;
#endif

private readonly global::System.Boolean _isInitialized;

private readonly System.Guid _value;

/// <summary>
/// Gets the underlying <see cref="System.Guid" /> value if set, otherwise a <see cref="ValueObjectValidationException" /> is thrown.
/// </summary>
public readonly System.Guid Value
{
[global::System.Diagnostics.DebuggerStepThroughAttribute]
get
{
EnsureInitialized();
return _value;
}
}


[global::System.Diagnostics.DebuggerStepThroughAttribute]
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public MyVo()
{
#if DEBUG
_stackTrace = new global::System.Diagnostics.StackTrace();
#endif

_isInitialized = false;
_value = default;
}

[global::System.Diagnostics.DebuggerStepThroughAttribute]
private MyVo(System.Guid 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 MyVo From(System.Guid value)
{




MyVo instance = new MyVo(value);

return instance;
}


public static explicit operator MyVo(System.Guid value) => From(value);
public static explicit operator System.Guid(MyVo value) => value.Value;
public static MyVo FromNewGuid() { return From(global::System.Guid.NewGuid()); }
// only called internally when something has been deserialized into
// its primitive type.
private static MyVo Deserialize(System.Guid value)
{




return new MyVo(value);
}
public readonly global::System.Boolean Equals(MyVo 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.Guid>.Default.Equals(Value, other.Value);
}
public global::System.Boolean Equals(MyVo other, global::System.Collections.Generic.IEqualityComparer<MyVo> comparer)
{
return comparer.Equals(this, other);
}


public readonly global::System.Boolean Equals(System.Guid primitive)
{
return Value.Equals(primitive);
}

public readonly override global::System.Boolean Equals(global::System.Object obj)
{
return obj is MyVo && Equals((MyVo) obj);
}

public static global::System.Boolean operator ==(MyVo left, MyVo right) => Equals(left, right);
public static global::System.Boolean operator !=(MyVo left, MyVo right) => !(left == right);

public static global::System.Boolean operator ==(MyVo left, System.Guid right) => Equals(left.Value, right);
public static global::System.Boolean operator !=(MyVo left, System.Guid right) => !Equals(left.Value, right);

public static global::System.Boolean operator ==(System.Guid left, MyVo right) => Equals(left, right.Value);
public static global::System.Boolean operator !=(System.Guid left, MyVo right) => !Equals(left, right.Value);

public int CompareTo(MyVo other) => Value.CompareTo(other.Value);
public int CompareTo(object other) {
if(other is null) return 1;
if(other is MyVo x) return CompareTo(x);
throw new global::System.ArgumentException("Cannot compare to object as it is not of type MyVo", nameof(other));
}


/// <inheritdoc cref="System.Guid.TryParse(System.ReadOnlySpan{char}, out System.Guid)"/>
/// <summary>
/// </summary>
/// <returns>
/// True if the value could a) be parsed by the underlying type, and b) passes any validation (after running any optional normalization).
/// </returns>
public static global::System.Boolean TryParse(global::System.ReadOnlySpan<char> input,
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
out MyVo result) {
if(System.Guid.TryParse(input, out var __v)) {


result = new MyVo(__v);
return true;
}

result = default;
return false;
}

/// <inheritdoc cref="System.Guid.TryParse(string?, out System.Guid)"/>
/// <summary>
/// </summary>
/// <returns>
/// True if the value could a) be parsed by the underlying type, and b) passes any validation (after running any optional normalization).
/// </returns>
public static global::System.Boolean TryParse(string input,
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
out MyVo result) {
if(System.Guid.TryParse(input, out var __v)) {


result = new MyVo(__v);
return true;
}

result = default;
return false;
}

/// <inheritdoc cref="System.Guid.Parse(System.ReadOnlySpan{char})"/>
/// <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 MyVo Parse(global::System.ReadOnlySpan<char> input) {
var r = System.Guid.Parse(input);
return From(r);
}

/// <inheritdoc cref="System.Guid.Parse(string)"/>
/// <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 MyVo Parse(string input) {
var r = System.Guid.Parse(input);
return From(r);
}



public readonly override global::System.Int32 GetHashCode()
{
return global::System.Collections.Generic.EqualityComparer<System.Guid>.Default.GetHashCode(Value);
}

/// <summary>Returns the string representation of the underlying type</summary>
/// <inheritdoc cref="System.Guid.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 MyVoSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter<MyVo>
{
public override MyVo Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
{
return MyVo.Deserialize(System.Guid.Parse(reader.GetString()));
}

public override void Write(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options)
{
writer.WriteStringValue(value.Value);
}

#if NET6_0_OR_GREATER
public override MyVo ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
{
return MyVo.Deserialize(System.Guid.Parse(reader.GetString()));
}

public override void WriteAsPropertyName(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options)
{
writer.WritePropertyName(value.Value.ToString());
}
#endif
}


class MyVoTypeConverter : global::System.ComponentModel.TypeConverter
{
public override global::System.Boolean CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Type sourceType)
{
return sourceType == typeof(global::System.Guid) || 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.Guid guidValue => MyVo.Deserialize(guidValue),
global::System.String stringValue when !global::System.String.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => MyVo.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.Guid) || 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 MyVo idValue)
{
if (destinationType == typeof(global::System.Guid))
{
return idValue.Value;
}

if (destinationType == typeof(global::System.String))
{
return idValue.Value.ToString();
}
}

return base.ConvertTo(context, culture, value, destinationType);
}
}






internal sealed class MyVoDebugView
{
private readonly MyVo _t;

MyVoDebugView(MyVo t)
{
_t = t;
}

public global::System.Boolean IsInitialized => _t._isInitialized;
public global::System.String UnderlyingType => "System.Guid";
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";
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,357 @@
// ------------------------------------------------------------------------------
// <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;


[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Vogen", "1.0.0.0")]
[global::System.Text.Json.Serialization.JsonConverter(typeof(MyVoSystemTextJsonConverter))]
[global::System.ComponentModel.TypeConverter(typeof(MyVoTypeConverter))]

[global::System.Diagnostics.DebuggerTypeProxyAttribute(typeof(MyVoDebugView))]
[global::System.Diagnostics.DebuggerDisplayAttribute("Underlying type: System.Guid, Value = { _value }")]
public partial record class MyVo : global::System.IEquatable<MyVo>, global::System.IEquatable<System.Guid>, global::System.IComparable<MyVo>, global::System.IComparable
{
#if DEBUG
private readonly global::System.Diagnostics.StackTrace _stackTrace = null;
#endif
private readonly global::System.Boolean _isInitialized;
private readonly System.Guid _value;

/// <summary>
/// Gets the underlying <see cref="System.Guid" /> value if set, otherwise a <see cref="ValueObjectValidationException" /> is thrown.
/// </summary>
public System.Guid Value
{
[global::System.Diagnostics.DebuggerStepThroughAttribute]
get
{
EnsureInitialized();
return _value;
}
[global::System.Diagnostics.DebuggerStepThroughAttribute]
init
{






_value = value;
}
}


[global::System.Diagnostics.DebuggerStepThroughAttribute]
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public MyVo()
{
#if DEBUG
_stackTrace = new global::System.Diagnostics.StackTrace();
#endif
_isInitialized = false;
_value = default;
}

[global::System.Diagnostics.DebuggerStepThroughAttribute]
private MyVo(System.Guid 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 MyVo From(System.Guid value)
{






MyVo instance = new MyVo(value);

return instance;
}

// only called internally when something has been deserialized into
// its primitive type.
private static MyVo Deserialize(System.Guid value)
{






return new MyVo(value);
}

public virtual global::System.Boolean Equals(MyVo other)
{
if (ReferenceEquals(null, other))
{
return false;
}

// 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;

if (ReferenceEquals(this, other))
{
return true;
}

return GetType() == other.GetType() && global::System.Collections.Generic.EqualityComparer<System.Guid>.Default.Equals(Value, other.Value);
}
public global::System.Boolean Equals(MyVo other, global::System.Collections.Generic.IEqualityComparer<MyVo> comparer)
{
return comparer.Equals(this, other);
}


public global::System.Boolean Equals(System.Guid primitive)
{
return Value.Equals(primitive);
}


public static global::System.Boolean operator ==(MyVo left, System.Guid right) => Equals(left.Value, right);
public static global::System.Boolean operator !=(MyVo left, System.Guid right) => !Equals(left.Value, right);

public static global::System.Boolean operator ==(System.Guid left, MyVo right) => Equals(left, right.Value);
public static global::System.Boolean operator !=(System.Guid left, MyVo right) => !Equals(left, right.Value);

public static explicit operator MyVo(System.Guid value) => From(value);
public static explicit operator System.Guid(MyVo value) => value.Value;
public static MyVo FromNewGuid() { return From(global::System.Guid.NewGuid()); }
public int CompareTo(MyVo other) => Value.CompareTo(other.Value);
public int CompareTo(object other) {
if(other is null) return 1;
if(other is MyVo x) return CompareTo(x);
throw new global::System.ArgumentException("Cannot compare to object as it is not of type MyVo", nameof(other));
}


/// <inheritdoc cref="System.Guid.TryParse(System.ReadOnlySpan{char}, out System.Guid)"/>
/// <summary>
/// </summary>
/// <returns>
/// True if the value could a) be parsed by the underlying type, and b) passes any validation (after running any optional normalization).
/// </returns>
public static global::System.Boolean TryParse(global::System.ReadOnlySpan<char> input,
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
out MyVo result) {
if(System.Guid.TryParse(input, out var __v)) {


result = new MyVo(__v);
return true;
}

result = default;
return false;
}

/// <inheritdoc cref="System.Guid.TryParse(string?, out System.Guid)"/>
/// <summary>
/// </summary>
/// <returns>
/// True if the value could a) be parsed by the underlying type, and b) passes any validation (after running any optional normalization).
/// </returns>
public static global::System.Boolean TryParse(string input,
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
out MyVo result) {
if(System.Guid.TryParse(input, out var __v)) {


result = new MyVo(__v);
return true;
}

result = default;
return false;
}

/// <inheritdoc cref="System.Guid.Parse(System.ReadOnlySpan{char})"/>
/// <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 MyVo Parse(global::System.ReadOnlySpan<char> input) {
var r = System.Guid.Parse(input);
return From(r);
}

/// <inheritdoc cref="System.Guid.Parse(string)"/>
/// <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 MyVo Parse(string input) {
var r = System.Guid.Parse(input);
return From(r);
}



public override global::System.Int32 GetHashCode()
{
unchecked // Overflow is fine, just wrap
{
global::System.Int32 hash = (global::System.Int32) 2166136261;
hash = (hash * 16777619) ^ GetType().GetHashCode();
hash = (hash * 16777619) ^ global::System.Collections.Generic.EqualityComparer<System.Guid>.Default.GetHashCode(Value);
return hash;
}
}

private 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);
}
}




// record enumerates fields - we just want our Value and to throw if it's not initialized.
/// <summary>Returns the string representation of the underlying <see cref="System.Guid" />.</summary>
/// <inheritdoc cref="System.Guid.ToString()" />
public override global::System.String ToString() => _isInitialized ? Value.ToString() : "[UNINITIALIZED]";


class MyVoSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter<MyVo>
{
public override MyVo Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
{
return MyVo.Deserialize(System.Guid.Parse(reader.GetString()));
}

public override void Write(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options)
{
writer.WriteStringValue(value.Value);
}

#if NET6_0_OR_GREATER
public override MyVo ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
{
return MyVo.Deserialize(System.Guid.Parse(reader.GetString()));
}

public override void WriteAsPropertyName(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options)
{
writer.WritePropertyName(value.Value.ToString());
}
#endif
}


class MyVoTypeConverter : global::System.ComponentModel.TypeConverter
{
public override global::System.Boolean CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Type sourceType)
{
return sourceType == typeof(global::System.Guid) || 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.Guid guidValue => MyVo.Deserialize(guidValue),
global::System.String stringValue when !global::System.String.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => MyVo.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.Guid) || 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 MyVo idValue)
{
if (destinationType == typeof(global::System.Guid))
{
return idValue.Value;
}

if (destinationType == typeof(global::System.String))
{
return idValue.Value.ToString();
}
}

return base.ConvertTo(context, culture, value, destinationType);
}
}





internal sealed class MyVoDebugView
{
private readonly MyVo _t;

MyVoDebugView(MyVo t)
{
_t = t;
}

public global::System.String UnderlyingType => "System.Guid";
public System.Guid Value => _t.Value ;

public global::System.String Conversions => @"[global::System.Text.Json.Serialization.JsonConverter(typeof(MyVoSystemTextJsonConverter))]
[global::System.ComponentModel.TypeConverter(typeof(MyVoTypeConverter))]
";
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,353 @@
// ------------------------------------------------------------------------------
// <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;


[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Vogen", "1.0.0.0")]
[global::System.Text.Json.Serialization.JsonConverter(typeof(MyVoSystemTextJsonConverter))]
[global::System.ComponentModel.TypeConverter(typeof(MyVoTypeConverter))]

[global::System.Diagnostics.DebuggerTypeProxyAttribute(typeof(MyVoDebugView))]
[global::System.Diagnostics.DebuggerDisplayAttribute("Underlying type: System.Guid, Value = { _value }")]
public partial class MyVo : global::System.IEquatable<MyVo>, global::System.IEquatable<System.Guid> , global::System.IComparable<MyVo>, global::System.IComparable
{
#if DEBUG
private readonly global::System.Diagnostics.StackTrace _stackTrace = null;
#endif
private readonly global::System.Boolean _isInitialized;
private readonly System.Guid _value;

/// <summary>
/// Gets the underlying <see cref="System.Guid" /> value if set, otherwise a <see cref="ValueObjectValidationException" /> is thrown.
/// </summary>
public System.Guid Value
{
[global::System.Diagnostics.DebuggerStepThroughAttribute]
get
{
EnsureInitialized();
return _value;
}
}


[global::System.Diagnostics.DebuggerStepThroughAttribute]
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public MyVo()
{
#if DEBUG
_stackTrace = new global::System.Diagnostics.StackTrace();
#endif
_isInitialized = false;
_value = default;
}

[global::System.Diagnostics.DebuggerStepThroughAttribute]
private MyVo(System.Guid 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 MyVo From(System.Guid value)
{






MyVo instance = new MyVo(value);

return instance;
}


// only called internally when something has been deserialized into
// its primitive type.
private static MyVo Deserialize(System.Guid value)
{






return new MyVo(value);
}

public global::System.Boolean Equals(MyVo other)
{
if (ReferenceEquals(null, other))
{
return false;
}

// 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;

if (ReferenceEquals(this, other))
{
return true;
}

return GetType() == other.GetType() && global::System.Collections.Generic.EqualityComparer<System.Guid>.Default.Equals(Value, other.Value);
}
public global::System.Boolean Equals(MyVo other, global::System.Collections.Generic.IEqualityComparer<MyVo> comparer)
{
return comparer.Equals(this, other);
}


public global::System.Boolean Equals(System.Guid primitive)
{
return Value.Equals(primitive);
}

public override global::System.Boolean Equals(global::System.Object obj)
{
return Equals(obj as MyVo);
}

public static global::System.Boolean operator ==(MyVo left, MyVo right) => Equals(left, right);
public static global::System.Boolean operator !=(MyVo left, MyVo right) => !Equals(left, right);

public static global::System.Boolean operator ==(MyVo left, System.Guid right) => Equals(left.Value, right);
public static global::System.Boolean operator !=(MyVo left, System.Guid right) => !Equals(left.Value, right);

public static global::System.Boolean operator ==(System.Guid left, MyVo right) => Equals(left, right.Value);
public static global::System.Boolean operator !=(System.Guid left, MyVo right) => !Equals(left, right.Value);

public static explicit operator MyVo(System.Guid value) => From(value);
public static explicit operator System.Guid(MyVo value) => value.Value;
public static MyVo FromNewGuid() { return From(global::System.Guid.NewGuid()); }
public int CompareTo(MyVo other) => Value.CompareTo(other.Value);
public int CompareTo(object other) {
if(other is null) return 1;
if(other is MyVo x) return CompareTo(x);
throw new global::System.ArgumentException("Cannot compare to object as it is not of type MyVo", nameof(other));
}


/// <inheritdoc cref="System.Guid.TryParse(System.ReadOnlySpan{char}, out System.Guid)"/>
/// <summary>
/// </summary>
/// <returns>
/// True if the value could a) be parsed by the underlying type, and b) passes any validation (after running any optional normalization).
/// </returns>
public static global::System.Boolean TryParse(global::System.ReadOnlySpan<char> input,
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
out MyVo result) {
if(System.Guid.TryParse(input, out var __v)) {


result = new MyVo(__v);
return true;
}

result = default;
return false;
}

/// <inheritdoc cref="System.Guid.TryParse(string?, out System.Guid)"/>
/// <summary>
/// </summary>
/// <returns>
/// True if the value could a) be parsed by the underlying type, and b) passes any validation (after running any optional normalization).
/// </returns>
public static global::System.Boolean TryParse(string input,
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
out MyVo result) {
if(System.Guid.TryParse(input, out var __v)) {


result = new MyVo(__v);
return true;
}

result = default;
return false;
}

/// <inheritdoc cref="System.Guid.Parse(System.ReadOnlySpan{char})"/>
/// <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 MyVo Parse(global::System.ReadOnlySpan<char> input) {
var r = System.Guid.Parse(input);
return From(r);
}

/// <inheritdoc cref="System.Guid.Parse(string)"/>
/// <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 MyVo Parse(string input) {
var r = System.Guid.Parse(input);
return From(r);
}



public override global::System.Int32 GetHashCode()
{
unchecked // Overflow is fine, just wrap
{
global::System.Int32 hash = (global::System.Int32) 2166136261;
hash = (hash * 16777619) ^ GetType().GetHashCode();
hash = (hash * 16777619) ^ global::System.Collections.Generic.EqualityComparer<System.Guid>.Default.GetHashCode(Value);
return hash;
}
}

private 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);
}
}




/// <summary>Returns the string representation of the underlying <see cref="System.Guid" />.</summary>
/// <inheritdoc cref="System.Guid.ToString()" />
public override global::System.String ToString() => _isInitialized ? Value.ToString() : "[UNINITIALIZED]";


class MyVoSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter<MyVo>
{
public override MyVo Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
{
return MyVo.Deserialize(System.Guid.Parse(reader.GetString()));
}

public override void Write(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options)
{
writer.WriteStringValue(value.Value);
}

#if NET6_0_OR_GREATER
public override MyVo ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
{
return MyVo.Deserialize(System.Guid.Parse(reader.GetString()));
}

public override void WriteAsPropertyName(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options)
{
writer.WritePropertyName(value.Value.ToString());
}
#endif
}


class MyVoTypeConverter : global::System.ComponentModel.TypeConverter
{
public override global::System.Boolean CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Type sourceType)
{
return sourceType == typeof(global::System.Guid) || 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.Guid guidValue => MyVo.Deserialize(guidValue),
global::System.String stringValue when !global::System.String.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => MyVo.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.Guid) || 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 MyVo idValue)
{
if (destinationType == typeof(global::System.Guid))
{
return idValue.Value;
}

if (destinationType == typeof(global::System.String))
{
return idValue.Value.ToString();
}
}

return base.ConvertTo(context, culture, value, destinationType);
}
}





internal sealed class MyVoDebugView
{
private readonly MyVo _t;

MyVoDebugView(MyVo t)
{
_t = t;
}

public global::System.String UnderlyingType => "System.Guid";
public System.Guid Value => _t.Value ;

public global::System.String Conversions => @"[global::System.Text.Json.Serialization.JsonConverter(typeof(MyVoSystemTextJsonConverter))]
[global::System.ComponentModel.TypeConverter(typeof(MyVoTypeConverter))]
";
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,343 @@
// ------------------------------------------------------------------------------
// <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;


[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Vogen", "1.0.0.0")]
[global::System.Text.Json.Serialization.JsonConverter(typeof(MyVoSystemTextJsonConverter))]
[global::System.ComponentModel.TypeConverter(typeof(MyVoTypeConverter))]

[global::System.Diagnostics.DebuggerTypeProxyAttribute(typeof(MyVoDebugView))]
[global::System.Diagnostics.DebuggerDisplayAttribute("Underlying type: System.Guid, Value = { _value }")]
public partial record struct MyVo : global::System.IEquatable<MyVo>, global::System.IEquatable<System.Guid>, global::System.IComparable<MyVo>, global::System.IComparable
{
#if DEBUG
private readonly global::System.Diagnostics.StackTrace _stackTrace = null;
#endif

private readonly global::System.Boolean _isInitialized;

private readonly System.Guid _value;

/// <summary>
/// Gets the underlying <see cref="System.Guid" /> value if set, otherwise a <see cref="ValueObjectValidationException" /> is thrown.
/// </summary>
public readonly System.Guid Value
{
[global::System.Diagnostics.DebuggerStepThroughAttribute]
get
{
EnsureInitialized();
return _value;
}
[global::System.Diagnostics.DebuggerStepThroughAttribute]
init
{






_value = value;
}
}


[global::System.Diagnostics.DebuggerStepThroughAttribute]
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public MyVo()
{
#if DEBUG
_stackTrace = new global::System.Diagnostics.StackTrace();
#endif

_isInitialized = false;
_value = default;
}

[global::System.Diagnostics.DebuggerStepThroughAttribute]
private MyVo(System.Guid 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 MyVo From(System.Guid value)
{




MyVo instance = new MyVo(value);

return instance;
}

public static explicit operator MyVo(System.Guid value) => From(value);
public static explicit operator System.Guid(MyVo value) => value.Value;
public static MyVo FromNewGuid() { return From(global::System.Guid.NewGuid()); }
// only called internally when something has been deserialized into
// its primitive type.
private static MyVo Deserialize(System.Guid value)
{




return new MyVo(value);
}
public readonly global::System.Boolean Equals(MyVo 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.Guid>.Default.Equals(Value, other.Value);
}
public global::System.Boolean Equals(MyVo other, global::System.Collections.Generic.IEqualityComparer<MyVo> comparer)
{
return comparer.Equals(this, other);
}


public readonly global::System.Boolean Equals(System.Guid primitive)
{
return Value.Equals(primitive);
}


public static global::System.Boolean operator ==(MyVo left, System.Guid right) => Equals(left.Value, right);
public static global::System.Boolean operator !=(MyVo left, System.Guid right) => !Equals(left.Value, right);

public static global::System.Boolean operator ==(System.Guid left, MyVo right) => Equals(left, right.Value);
public static global::System.Boolean operator !=(System.Guid left, MyVo right) => !Equals(left, right.Value);

public int CompareTo(MyVo other) => Value.CompareTo(other.Value);
public int CompareTo(object other) {
if(other is null) return 1;
if(other is MyVo x) return CompareTo(x);
throw new global::System.ArgumentException("Cannot compare to object as it is not of type MyVo", nameof(other));
}


/// <inheritdoc cref="System.Guid.TryParse(System.ReadOnlySpan{char}, out System.Guid)"/>
/// <summary>
/// </summary>
/// <returns>
/// True if the value could a) be parsed by the underlying type, and b) passes any validation (after running any optional normalization).
/// </returns>
public static global::System.Boolean TryParse(global::System.ReadOnlySpan<char> input,
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
out MyVo result) {
if(System.Guid.TryParse(input, out var __v)) {


result = new MyVo(__v);
return true;
}

result = default;
return false;
}

/// <inheritdoc cref="System.Guid.TryParse(string?, out System.Guid)"/>
/// <summary>
/// </summary>
/// <returns>
/// True if the value could a) be parsed by the underlying type, and b) passes any validation (after running any optional normalization).
/// </returns>
public static global::System.Boolean TryParse(string input,
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
out MyVo result) {
if(System.Guid.TryParse(input, out var __v)) {


result = new MyVo(__v);
return true;
}

result = default;
return false;
}

/// <inheritdoc cref="System.Guid.Parse(System.ReadOnlySpan{char})"/>
/// <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 MyVo Parse(global::System.ReadOnlySpan<char> input) {
var r = System.Guid.Parse(input);
return From(r);
}

/// <inheritdoc cref="System.Guid.Parse(string)"/>
/// <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 MyVo Parse(string input) {
var r = System.Guid.Parse(input);
return From(r);
}



public readonly override global::System.Int32 GetHashCode()
{
return global::System.Collections.Generic.EqualityComparer<System.Guid>.Default.GetHashCode(Value);
}

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);
}
}

// record enumerates fields - we just want our Value and to throw if it's not initialized.
/// <summary>Returns the string representation of the underlying type</summary>
/// <inheritdoc cref="System.Guid.ToString()" />
public readonly override global::System.String ToString() =>_isInitialized ? Value.ToString() : "[UNINITIALIZED]";




class MyVoSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter<MyVo>
{
public override MyVo Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
{
return MyVo.Deserialize(System.Guid.Parse(reader.GetString()));
}

public override void Write(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options)
{
writer.WriteStringValue(value.Value);
}

#if NET6_0_OR_GREATER
public override MyVo ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
{
return MyVo.Deserialize(System.Guid.Parse(reader.GetString()));
}

public override void WriteAsPropertyName(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options)
{
writer.WritePropertyName(value.Value.ToString());
}
#endif
}


class MyVoTypeConverter : global::System.ComponentModel.TypeConverter
{
public override global::System.Boolean CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Type sourceType)
{
return sourceType == typeof(global::System.Guid) || 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.Guid guidValue => MyVo.Deserialize(guidValue),
global::System.String stringValue when !global::System.String.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => MyVo.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.Guid) || 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 MyVo idValue)
{
if (destinationType == typeof(global::System.Guid))
{
return idValue.Value;
}

if (destinationType == typeof(global::System.String))
{
return idValue.Value.ToString();
}
}

return base.ConvertTo(context, culture, value, destinationType);
}
}






internal sealed class MyVoDebugView
{
private readonly MyVo _t;

MyVoDebugView(MyVo t)
{
_t = t;
}

public global::System.Boolean IsInitialized => _t._isInitialized;
public global::System.String UnderlyingType => "System.Guid";
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";
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,305 @@
// ------------------------------------------------------------------------------
// <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;


[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Vogen", "1.0.0.0")]
[global::System.Text.Json.Serialization.JsonConverter(typeof(MyVoSystemTextJsonConverter))]
[global::System.ComponentModel.TypeConverter(typeof(MyVoTypeConverter))]

[global::System.Diagnostics.DebuggerTypeProxyAttribute(typeof(MyVoDebugView))]
[global::System.Diagnostics.DebuggerDisplayAttribute("Underlying type: System.Guid, Value = { _value }")]
public partial struct MyVo : global::System.IEquatable<MyVo>, global::System.IEquatable<System.Guid>, global::System.IComparable<MyVo>, global::System.IComparable
{
#if DEBUG
private readonly global::System.Diagnostics.StackTrace _stackTrace = null;
#endif

private readonly global::System.Boolean _isInitialized;

private readonly System.Guid _value;

/// <summary>
/// Gets the underlying <see cref="System.Guid" /> value if set, otherwise a <see cref="ValueObjectValidationException" /> is thrown.
/// </summary>
public readonly System.Guid Value
{
[global::System.Diagnostics.DebuggerStepThroughAttribute]
get
{
EnsureInitialized();
return _value;
}
}


[global::System.Diagnostics.DebuggerStepThroughAttribute]
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public MyVo()
{
#if DEBUG
_stackTrace = new global::System.Diagnostics.StackTrace();
#endif

_isInitialized = false;
_value = default;
}

[global::System.Diagnostics.DebuggerStepThroughAttribute]
private MyVo(System.Guid 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 MyVo From(System.Guid value)
{




MyVo instance = new MyVo(value);

return instance;
}


public static explicit operator MyVo(System.Guid value) => From(value);
public static explicit operator System.Guid(MyVo value) => value.Value;
public static MyVo FromNewGuid() { return From(global::System.Guid.NewGuid()); }
// only called internally when something has been deserialized into
// its primitive type.
private static MyVo Deserialize(System.Guid value)
{




return new MyVo(value);
}
public readonly global::System.Boolean Equals(MyVo 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.Guid>.Default.Equals(Value, other.Value);
}
public global::System.Boolean Equals(MyVo other, global::System.Collections.Generic.IEqualityComparer<MyVo> comparer)
{
return comparer.Equals(this, other);
}


public readonly global::System.Boolean Equals(System.Guid primitive)
{
return Value.Equals(primitive);
}

public readonly override global::System.Boolean Equals(global::System.Object obj)
{
return obj is MyVo && Equals((MyVo) obj);
}

public static global::System.Boolean operator ==(MyVo left, MyVo right) => Equals(left, right);
public static global::System.Boolean operator !=(MyVo left, MyVo right) => !(left == right);

public static global::System.Boolean operator ==(MyVo left, System.Guid right) => Equals(left.Value, right);
public static global::System.Boolean operator !=(MyVo left, System.Guid right) => !Equals(left.Value, right);

public static global::System.Boolean operator ==(System.Guid left, MyVo right) => Equals(left, right.Value);
public static global::System.Boolean operator !=(System.Guid left, MyVo right) => !Equals(left, right.Value);

public int CompareTo(MyVo other) => Value.CompareTo(other.Value);
public int CompareTo(object other) {
if(other is null) return 1;
if(other is MyVo x) return CompareTo(x);
throw new global::System.ArgumentException("Cannot compare to object as it is not of type MyVo", nameof(other));
}


/// <inheritdoc cref="System.Guid.TryParse(string, out System.Guid)"/>
/// <summary>
/// </summary>
/// <returns>
/// True if the value could a) be parsed by the underlying type, and b) passes any validation (after running any optional normalization).
/// </returns>
public static global::System.Boolean TryParse(string input,
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
out MyVo result) {
if(System.Guid.TryParse(input, out var __v)) {


result = new MyVo(__v);
return true;
}

result = default;
return false;
}

/// <inheritdoc cref="System.Guid.Parse(string)"/>
/// <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 MyVo Parse(string input) {
var r = System.Guid.Parse(input);
return From(r);
}



public readonly override global::System.Int32 GetHashCode()
{
return global::System.Collections.Generic.EqualityComparer<System.Guid>.Default.GetHashCode(Value);
}

/// <summary>Returns the string representation of the underlying type</summary>
/// <inheritdoc cref="System.Guid.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 MyVoSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter<MyVo>
{
public override MyVo Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
{
return MyVo.Deserialize(System.Guid.Parse(reader.GetString()));
}

public override void Write(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options)
{
writer.WriteStringValue(value.Value);
}

#if NET6_0_OR_GREATER
public override MyVo ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
{
return MyVo.Deserialize(System.Guid.Parse(reader.GetString()));
}

public override void WriteAsPropertyName(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options)
{
writer.WritePropertyName(value.Value.ToString());
}
#endif
}


class MyVoTypeConverter : global::System.ComponentModel.TypeConverter
{
public override global::System.Boolean CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Type sourceType)
{
return sourceType == typeof(global::System.Guid) || 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.Guid guidValue => MyVo.Deserialize(guidValue),
global::System.String stringValue when !global::System.String.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => MyVo.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.Guid) || 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 MyVo idValue)
{
if (destinationType == typeof(global::System.Guid))
{
return idValue.Value;
}

if (destinationType == typeof(global::System.String))
{
return idValue.Value.ToString();
}
}

return base.ConvertTo(context, culture, value, destinationType);
}
}






internal sealed class MyVoDebugView
{
private readonly MyVo _t;

MyVoDebugView(MyVo t)
{
_t = t;
}

public global::System.Boolean IsInitialized => _t._isInitialized;
public global::System.String UnderlyingType => "System.Guid";
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";
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,323 @@
// ------------------------------------------------------------------------------
// <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;


[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Vogen", "1.0.0.0")]
[global::System.Text.Json.Serialization.JsonConverter(typeof(MyVoSystemTextJsonConverter))]
[global::System.ComponentModel.TypeConverter(typeof(MyVoTypeConverter))]

[global::System.Diagnostics.DebuggerTypeProxyAttribute(typeof(MyVoDebugView))]
[global::System.Diagnostics.DebuggerDisplayAttribute("Underlying type: System.Guid, Value = { _value }")]
public partial record class MyVo : global::System.IEquatable<MyVo>, global::System.IEquatable<System.Guid>, global::System.IComparable<MyVo>, global::System.IComparable
{
#if DEBUG
private readonly global::System.Diagnostics.StackTrace _stackTrace = null;
#endif
private readonly global::System.Boolean _isInitialized;
private readonly System.Guid _value;

/// <summary>
/// Gets the underlying <see cref="System.Guid" /> value if set, otherwise a <see cref="ValueObjectValidationException" /> is thrown.
/// </summary>
public System.Guid Value
{
[global::System.Diagnostics.DebuggerStepThroughAttribute]
get
{
EnsureInitialized();
return _value;
}
[global::System.Diagnostics.DebuggerStepThroughAttribute]
init
{






_value = value;
}
}


[global::System.Diagnostics.DebuggerStepThroughAttribute]
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public MyVo()
{
#if DEBUG
_stackTrace = new global::System.Diagnostics.StackTrace();
#endif
_isInitialized = false;
_value = default;
}

[global::System.Diagnostics.DebuggerStepThroughAttribute]
private MyVo(System.Guid 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 MyVo From(System.Guid value)
{






MyVo instance = new MyVo(value);

return instance;
}

// only called internally when something has been deserialized into
// its primitive type.
private static MyVo Deserialize(System.Guid value)
{






return new MyVo(value);
}

public virtual global::System.Boolean Equals(MyVo other)
{
if (ReferenceEquals(null, other))
{
return false;
}

// 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;

if (ReferenceEquals(this, other))
{
return true;
}

return GetType() == other.GetType() && global::System.Collections.Generic.EqualityComparer<System.Guid>.Default.Equals(Value, other.Value);
}
public global::System.Boolean Equals(MyVo other, global::System.Collections.Generic.IEqualityComparer<MyVo> comparer)
{
return comparer.Equals(this, other);
}


public global::System.Boolean Equals(System.Guid primitive)
{
return Value.Equals(primitive);
}


public static global::System.Boolean operator ==(MyVo left, System.Guid right) => Equals(left.Value, right);
public static global::System.Boolean operator !=(MyVo left, System.Guid right) => !Equals(left.Value, right);

public static global::System.Boolean operator ==(System.Guid left, MyVo right) => Equals(left, right.Value);
public static global::System.Boolean operator !=(System.Guid left, MyVo right) => !Equals(left, right.Value);

public static explicit operator MyVo(System.Guid value) => From(value);
public static explicit operator System.Guid(MyVo value) => value.Value;
public static MyVo FromNewGuid() { return From(global::System.Guid.NewGuid()); }
public int CompareTo(MyVo other) => Value.CompareTo(other.Value);
public int CompareTo(object other) {
if(other is null) return 1;
if(other is MyVo x) return CompareTo(x);
throw new global::System.ArgumentException("Cannot compare to object as it is not of type MyVo", nameof(other));
}


/// <inheritdoc cref="System.Guid.TryParse(string, out System.Guid)"/>
/// <summary>
/// </summary>
/// <returns>
/// True if the value could a) be parsed by the underlying type, and b) passes any validation (after running any optional normalization).
/// </returns>
public static global::System.Boolean TryParse(string input,
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
out MyVo result) {
if(System.Guid.TryParse(input, out var __v)) {


result = new MyVo(__v);
return true;
}

result = default;
return false;
}

/// <inheritdoc cref="System.Guid.Parse(string)"/>
/// <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 MyVo Parse(string input) {
var r = System.Guid.Parse(input);
return From(r);
}



public override global::System.Int32 GetHashCode()
{
unchecked // Overflow is fine, just wrap
{
global::System.Int32 hash = (global::System.Int32) 2166136261;
hash = (hash * 16777619) ^ GetType().GetHashCode();
hash = (hash * 16777619) ^ global::System.Collections.Generic.EqualityComparer<System.Guid>.Default.GetHashCode(Value);
return hash;
}
}

private 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);
}
}




// record enumerates fields - we just want our Value and to throw if it's not initialized.
/// <summary>Returns the string representation of the underlying <see cref="System.Guid" />.</summary>
/// <inheritdoc cref="System.Guid.ToString()" />
public override global::System.String ToString() => _isInitialized ? Value.ToString() : "[UNINITIALIZED]";


class MyVoSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter<MyVo>
{
public override MyVo Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
{
return MyVo.Deserialize(System.Guid.Parse(reader.GetString()));
}

public override void Write(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options)
{
writer.WriteStringValue(value.Value);
}

#if NET6_0_OR_GREATER
public override MyVo ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
{
return MyVo.Deserialize(System.Guid.Parse(reader.GetString()));
}

public override void WriteAsPropertyName(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options)
{
writer.WritePropertyName(value.Value.ToString());
}
#endif
}


class MyVoTypeConverter : global::System.ComponentModel.TypeConverter
{
public override global::System.Boolean CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Type sourceType)
{
return sourceType == typeof(global::System.Guid) || 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.Guid guidValue => MyVo.Deserialize(guidValue),
global::System.String stringValue when !global::System.String.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => MyVo.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.Guid) || 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 MyVo idValue)
{
if (destinationType == typeof(global::System.Guid))
{
return idValue.Value;
}

if (destinationType == typeof(global::System.String))
{
return idValue.Value.ToString();
}
}

return base.ConvertTo(context, culture, value, destinationType);
}
}





internal sealed class MyVoDebugView
{
private readonly MyVo _t;

MyVoDebugView(MyVo t)
{
_t = t;
}

public global::System.String UnderlyingType => "System.Guid";
public System.Guid Value => _t.Value ;

public global::System.String Conversions => @"[global::System.Text.Json.Serialization.JsonConverter(typeof(MyVoSystemTextJsonConverter))]
[global::System.ComponentModel.TypeConverter(typeof(MyVoTypeConverter))]
";
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,319 @@
// ------------------------------------------------------------------------------
// <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;


[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Vogen", "1.0.0.0")]
[global::System.Text.Json.Serialization.JsonConverter(typeof(MyVoSystemTextJsonConverter))]
[global::System.ComponentModel.TypeConverter(typeof(MyVoTypeConverter))]

[global::System.Diagnostics.DebuggerTypeProxyAttribute(typeof(MyVoDebugView))]
[global::System.Diagnostics.DebuggerDisplayAttribute("Underlying type: System.Guid, Value = { _value }")]
public partial class MyVo : global::System.IEquatable<MyVo>, global::System.IEquatable<System.Guid> , global::System.IComparable<MyVo>, global::System.IComparable
{
#if DEBUG
private readonly global::System.Diagnostics.StackTrace _stackTrace = null;
#endif
private readonly global::System.Boolean _isInitialized;
private readonly System.Guid _value;

/// <summary>
/// Gets the underlying <see cref="System.Guid" /> value if set, otherwise a <see cref="ValueObjectValidationException" /> is thrown.
/// </summary>
public System.Guid Value
{
[global::System.Diagnostics.DebuggerStepThroughAttribute]
get
{
EnsureInitialized();
return _value;
}
}


[global::System.Diagnostics.DebuggerStepThroughAttribute]
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
public MyVo()
{
#if DEBUG
_stackTrace = new global::System.Diagnostics.StackTrace();
#endif
_isInitialized = false;
_value = default;
}

[global::System.Diagnostics.DebuggerStepThroughAttribute]
private MyVo(System.Guid 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 MyVo From(System.Guid value)
{






MyVo instance = new MyVo(value);

return instance;
}


// only called internally when something has been deserialized into
// its primitive type.
private static MyVo Deserialize(System.Guid value)
{






return new MyVo(value);
}

public global::System.Boolean Equals(MyVo other)
{
if (ReferenceEquals(null, other))
{
return false;
}

// 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;

if (ReferenceEquals(this, other))
{
return true;
}

return GetType() == other.GetType() && global::System.Collections.Generic.EqualityComparer<System.Guid>.Default.Equals(Value, other.Value);
}
public global::System.Boolean Equals(MyVo other, global::System.Collections.Generic.IEqualityComparer<MyVo> comparer)
{
return comparer.Equals(this, other);
}


public global::System.Boolean Equals(System.Guid primitive)
{
return Value.Equals(primitive);
}

public override global::System.Boolean Equals(global::System.Object obj)
{
return Equals(obj as MyVo);
}

public static global::System.Boolean operator ==(MyVo left, MyVo right) => Equals(left, right);
public static global::System.Boolean operator !=(MyVo left, MyVo right) => !Equals(left, right);

public static global::System.Boolean operator ==(MyVo left, System.Guid right) => Equals(left.Value, right);
public static global::System.Boolean operator !=(MyVo left, System.Guid right) => !Equals(left.Value, right);

public static global::System.Boolean operator ==(System.Guid left, MyVo right) => Equals(left, right.Value);
public static global::System.Boolean operator !=(System.Guid left, MyVo right) => !Equals(left, right.Value);

public static explicit operator MyVo(System.Guid value) => From(value);
public static explicit operator System.Guid(MyVo value) => value.Value;
public static MyVo FromNewGuid() { return From(global::System.Guid.NewGuid()); }
public int CompareTo(MyVo other) => Value.CompareTo(other.Value);
public int CompareTo(object other) {
if(other is null) return 1;
if(other is MyVo x) return CompareTo(x);
throw new global::System.ArgumentException("Cannot compare to object as it is not of type MyVo", nameof(other));
}


/// <inheritdoc cref="System.Guid.TryParse(string, out System.Guid)"/>
/// <summary>
/// </summary>
/// <returns>
/// True if the value could a) be parsed by the underlying type, and b) passes any validation (after running any optional normalization).
/// </returns>
public static global::System.Boolean TryParse(string input,
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
out MyVo result) {
if(System.Guid.TryParse(input, out var __v)) {


result = new MyVo(__v);
return true;
}

result = default;
return false;
}

/// <inheritdoc cref="System.Guid.Parse(string)"/>
/// <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 MyVo Parse(string input) {
var r = System.Guid.Parse(input);
return From(r);
}



public override global::System.Int32 GetHashCode()
{
unchecked // Overflow is fine, just wrap
{
global::System.Int32 hash = (global::System.Int32) 2166136261;
hash = (hash * 16777619) ^ GetType().GetHashCode();
hash = (hash * 16777619) ^ global::System.Collections.Generic.EqualityComparer<System.Guid>.Default.GetHashCode(Value);
return hash;
}
}

private 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);
}
}




/// <summary>Returns the string representation of the underlying <see cref="System.Guid" />.</summary>
/// <inheritdoc cref="System.Guid.ToString()" />
public override global::System.String ToString() => _isInitialized ? Value.ToString() : "[UNINITIALIZED]";


class MyVoSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter<MyVo>
{
public override MyVo Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
{
return MyVo.Deserialize(System.Guid.Parse(reader.GetString()));
}

public override void Write(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options)
{
writer.WriteStringValue(value.Value);
}

#if NET6_0_OR_GREATER
public override MyVo ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
{
return MyVo.Deserialize(System.Guid.Parse(reader.GetString()));
}

public override void WriteAsPropertyName(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options)
{
writer.WritePropertyName(value.Value.ToString());
}
#endif
}


class MyVoTypeConverter : global::System.ComponentModel.TypeConverter
{
public override global::System.Boolean CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Type sourceType)
{
return sourceType == typeof(global::System.Guid) || 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.Guid guidValue => MyVo.Deserialize(guidValue),
global::System.String stringValue when !global::System.String.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => MyVo.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.Guid) || 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 MyVo idValue)
{
if (destinationType == typeof(global::System.Guid))
{
return idValue.Value;
}

if (destinationType == typeof(global::System.String))
{
return idValue.Value.ToString();
}
}

return base.ConvertTo(context, culture, value, destinationType);
}
}





internal sealed class MyVoDebugView
{
private readonly MyVo _t;

MyVoDebugView(MyVo t)
{
_t = t;
}

public global::System.String UnderlyingType => "System.Guid";
public System.Guid Value => _t.Value ;

public global::System.String Conversions => @"[global::System.Text.Json.Serialization.JsonConverter(typeof(MyVoSystemTextJsonConverter))]
[global::System.ComponentModel.TypeConverter(typeof(MyVoTypeConverter))]
";
}
}

Loading

0 comments on commit 60c8037

Please sign in to comment.