diff --git a/docs/site/Writerside/topics/how-to/conversion-mechanisms.md b/docs/site/Writerside/topics/how-to/conversion-mechanisms.md index dc43b733b8..abce224062 100644 --- a/docs/site/Writerside/topics/how-to/conversion-mechanisms.md +++ b/docs/site/Writerside/topics/how-to/conversion-mechanisms.md @@ -339,7 +339,7 @@ public class Customer { [BsonId] public CustomerId Id { get; set; } - + public string Name { get; set; } } @@ -347,6 +347,26 @@ public class Customer var customer = collection.Find(c => c.Id == customerId).FirstOrDefault(); ``` +**Registration Options:** + +By default, Vogen generates a static class with a static constructor that automatically registers BSON serializers. +If you need to configure BSON before registration (e.g., custom serializers, conventions), use: + +```c# +[assembly: VogenDefaults( + conversions: Conversions.Bson, + customizations: Customizations.ManuallyRegisterBsonSerializers)] + +// Now you control when registration happens: +// 1. Configure BSON as needed +BsonSerializer.RegisterSerializer(new CustomSerializer()); + +// 2. Then register Vogen serializers +BsonSerializationRegisterFor[YourProjectName].TryRegister(); +``` + +See [MongoDB Integration](MongoIntegrationHowTo.md) for details. + ### MessagePack ```c# diff --git a/docs/site/Writerside/topics/reference/Configuration.md b/docs/site/Writerside/topics/reference/Configuration.md index 99e35467cf..856180c56d 100644 --- a/docs/site/Writerside/topics/reference/Configuration.md +++ b/docs/site/Writerside/topics/reference/Configuration.md @@ -20,7 +20,11 @@ Most values are present in both `ValueObject` and `VogenDefaults`. The parameter * `underlyingType`—the type of the primitive that is being wrapped—defaults to `int` * `conversions` - specified what conversion code is generated - defaults to `Conversions.Default` which generates type converters and a converter to handle serialization using System.Text.Json * `throws` = specifies the type of exception thrown when validation fails—defaults to `ValueObjectValidationException` -* `customizations`—simple customization switches—defaults to `Customizations.None`, +* `customizations`—simple customization switches—defaults to `Customizations.None`. Available flags: + * `Customizations.TreatNumberAsStringInSystemTextJson` - serialize numbers as strings in System.Text.Json (obsolete on .NET 5+) + * `Customizations.AddFactoryMethodForGuids` - adds a `FromNewGuid()` factory method for GUID value objects + * `Customizations.GenerateLinqPadToDump` - generates a `ToDump()` method for LinqPad + * `Customizations.ManuallyRegisterBsonSerializers` - generates BSON registration as a `TryRegister()` method without a static constructor, allowing control over registration timing, * `deserializationStrictness` - specifies how strict deserialization is, e.g. should your `Validate` method be called, or should pre-defined instances that otherwise invalid be allowed - defaults to `DeserializationStrictness.AllowValidAndKnownInstances` * `debuggerAttributes` - specifies the level that debug attributes are written as some IDEs don't support all of them, e.g., Rider - defaults to `DebuggerAttributeGeneration.Full` which generates `DebuggerDisplay` and a debugger proxy type for IDEs that support them * `comparison`—species which comparison code is generated—defaults to `ComparisonGeneration.UseUnderlying` which hoists any `IComparable` implementations from the primitive diff --git a/docs/site/Writerside/topics/reference/FAQ.md b/docs/site/Writerside/topics/reference/FAQ.md index 965122826a..882ab3ee11 100644 --- a/docs/site/Writerside/topics/reference/FAQ.md +++ b/docs/site/Writerside/topics/reference/FAQ.md @@ -451,7 +451,30 @@ var newCustomerId = CustomerId.FromNewGuid(); ``` > To customize the generation of Guids, please see [this tutorial](Working-with-IDs.md) -> +> + +## How do I control when BSON serializers are registered? + +By default, Vogen generates a static class with a static constructor that automatically registers BSON serializers when first accessed. +If you need to run BSON configuration before registration (e.g., set up custom conventions, configure serializers), use: + +```c# +[assembly: VogenDefaults( + customizations: Customizations.ManuallyRegisterBsonSerializers)] +``` + +This generates a `TryRegister()` method without a static constructor, giving you full control: + +```c# +// 1. Configure BSON as needed +BsonSerializer.RegisterSerializer(new MyCustomSerializer()); +ConventionRegistry.Register("MyConventions", new ConventionPack { ... }, _ => true); + +// 2. Then register Vogen-generated serializers +BsonSerializationRegisterFor[YourProjectName].TryRegister(); +``` + +See [MongoDB Integration](MongoIntegrationHowTo.md) for more details. ## Can I use value objects instead of primitives as parameters in Blazor pages and components? diff --git a/docs/site/Writerside/topics/reference/MongoIntegrationHowTo.md b/docs/site/Writerside/topics/reference/MongoIntegrationHowTo.md index d3b34883a3..3634622ee9 100644 --- a/docs/site/Writerside/topics/reference/MongoIntegrationHowTo.md +++ b/docs/site/Writerside/topics/reference/MongoIntegrationHowTo.md @@ -14,7 +14,22 @@ public partial class Name Now that the serializers are generated, you now need to register them. Vogen generates a static class named `RegisterBsonSerializersFor[NameOfProject]`. -This static class has a static method named `TryRegister`, which registers the serializers if they're not already registered, e.g.: + +By default, this class has a static constructor that automatically registers all BSON serializers when first accessed. +However, if you need to run BSON configuration before the serializers are registered, you can use the `ManuallyRegisterBsonSerializers` customization: + +```c# +[assembly: VogenDefaults(customizations: Customizations.ManuallyRegisterBsonSerializers)] +``` + +With this flag set, Vogen generates a `TryRegister()` method without a static constructor, allowing you to control when registration occurs: + +```C# +// Call this manually after any BSON configuration +BsonSerializationRegisterFor[YourProjectName].TryRegister(); +``` + +Without the flag, the static constructor automatically calls code like: ```C# BsonSerializer.TryRegisterSerializer(new CustomerIdBsonSerializer()); @@ -54,4 +69,8 @@ BsonSerializationRegisterForVogen_Examples.TryRegister(); (_replace `Vogen_Examples` with the name of *your* project_) +> **Note:** By default, the static class has a static constructor that automatically registers serializers when first accessed. +> If you need control over when registration happens (e.g., to configure BSON first), use the `Customizations.ManuallyRegisterBsonSerializers` flag +> to generate only the `TryRegister()` method without the static constructor. + Next, it adds a bunch of `Person` objects to the database, each containing value objects representing age and name, and then reads them back. \ No newline at end of file diff --git a/src/Vogen.SharedTypes/Customizations.cs b/src/Vogen.SharedTypes/Customizations.cs index bf3e5e6a74..eee3a7f6b6 100644 --- a/src/Vogen.SharedTypes/Customizations.cs +++ b/src/Vogen.SharedTypes/Customizations.cs @@ -36,5 +36,13 @@ public enum Customizations /// /// Generate ToDump for LinqPad /// - GenerateLinqPadToDump = 1 << 2 + GenerateLinqPadToDump = 1 << 2, + + /// + /// Manually register BSON registrations. By default, Vogen creates a static class with a static constructor that registers + /// all BSON serializers. However, you might want to run BSON configuration before this. + /// This flag tells Vogen to create a `TryRegister` method on a class named `BsonSerializationRegisterFor[YourAssemblyName]` + /// as opposed to a static constructor + /// + ManuallyRegisterBsonSerializers = 1 << 3 } \ No newline at end of file diff --git a/src/Vogen/GenerateCodeForBsonSerializers.cs b/src/Vogen/GenerateCodeForBsonSerializers.cs index 4eb5e17fa3..1968a0e756 100644 --- a/src/Vogen/GenerateCodeForBsonSerializers.cs +++ b/src/Vogen/GenerateCodeForBsonSerializers.cs @@ -9,7 +9,7 @@ namespace Vogen; internal class GenerateCodeForBsonSerializers { private const string _nameSuffix = "BsonSerializer"; - + /// /// For each value object that has a BSON conversion attribute, write a separate file with a serializer, /// with a class name of '[WrapperName]BsonSerializer', and a filename of '[NameSpace].[WrapperName]_bson.g.cs' @@ -17,7 +17,11 @@ internal class GenerateCodeForBsonSerializers /// /// /// - public static void GenerateForApplicableValueObjects(SourceProductionContext context, Compilation compilation, List workItems) + /// + public static void GenerateForApplicableValueObjects(SourceProductionContext context, + Compilation compilation, + List workItems, + Customizations? customizations) { if (!compilation.IsAtLeastCSharp12()) { @@ -35,7 +39,7 @@ public static void GenerateForApplicableValueObjects(SourceProductionContext con Util.AddSourceToContext(filename, context, Util.FormatSource(eachGenerated)); } - WriteRegistration(applicableWrappers, compilation, context); + WriteRegistration(applicableWrappers, compilation, context, customizations); } /// @@ -131,7 +135,10 @@ string GenerateSerializers() } } - private static void WriteRegistration(List items, Compilation compilation, SourceProductionContext context) + private static void WriteRegistration(List items, + Compilation compilation, + SourceProductionContext context, + Customizations? customizations) { if (items.Count == 0) { @@ -140,20 +147,7 @@ private static void WriteRegistration(List items, Compilation compil var classNameForRegistering = ClassNameForRegistering(); - string source = - $$""" - {{GeneratedCodeSegments.Preamble}} - - public static class {{classNameForRegistering}} - { - static {{classNameForRegistering}}() - { - {{TextForEachRegisterCall(items)}} - } - - public static void TryRegister() { } - } - """; + var source = GenerateRegistrationSource(); Util.AddSourceToContext(classNameForRegistering, context, Util.FormatSource(source)); return; @@ -170,6 +164,37 @@ string ClassNameForRegistering() return s; } + + string GenerateRegistrationSource() + { + bool manual = customizations is not null && customizations.Value.HasFlag(Customizations.ManuallyRegisterBsonSerializers); + + return manual + ? $$""" + {{GeneratedCodeSegments.Preamble}} + + public static class {{classNameForRegistering}} + { + public static void TryRegister() + { + {{TextForEachRegisterCall(items)}} + } + } + """ + : $$""" + {{GeneratedCodeSegments.Preamble}} + + public static class {{classNameForRegistering}} + { + static {{classNameForRegistering}}() + { + {{TextForEachRegisterCall(items)}} + } + + public static void TryRegister() { } + } + """; + } } private static string TextForEachRegisterCall(List wrappers) diff --git a/src/Vogen/ValueObjectGenerator.cs b/src/Vogen/ValueObjectGenerator.cs index 61856f8798..2117039250 100644 --- a/src/Vogen/ValueObjectGenerator.cs +++ b/src/Vogen/ValueObjectGenerator.cs @@ -136,7 +136,7 @@ private static void Execute( GenerateCodeForMessagePack.GenerateForApplicableValueObjects(spc, compilation, workItems); GenerateCodeForMessagePack.GenerateForMarkerClasses(spc, markerClasses); - GenerateCodeForBsonSerializers.GenerateForApplicableValueObjects(spc, compilation, workItems); + GenerateCodeForBsonSerializers.GenerateForApplicableValueObjects(spc, compilation, workItems, globalConfig?.Customizations); GenerateCodeForBsonSerializers.GenerateForMarkerClasses(spc, markerClasses); GenerateCodeForOrleansSerializers.WriteIfNeeded(spc, workItems); diff --git a/tests/SnapshotTests/BsonSerializationGeneration/BsonSerializationGenerationTests.cs b/tests/SnapshotTests/BsonSerializationGeneration/BsonSerializationGenerationTests.cs index bbe8e8a48a..316e24f76b 100644 --- a/tests/SnapshotTests/BsonSerializationGeneration/BsonSerializationGenerationTests.cs +++ b/tests/SnapshotTests/BsonSerializationGeneration/BsonSerializationGenerationTests.cs @@ -29,6 +29,29 @@ public partial struct Name; .RunOn(TargetFramework.Net8_0); } + [Fact] + public async Task Writes_bson_serializers_but_manually_register_the_serializers() + { + var source = """ + using System; + using Vogen; + + [assembly: VogenDefaults(conversions: Conversions.Bson, customizations: Customizations.ManuallyRegisterBsonSerializers)] + + namespace Whatever; + [ValueObject] + public partial struct Age; + + [ValueObject] + public partial struct Name; + """; + + await new SnapshotRunner() + .WithSource(source) + .IgnoreInitialCompilationErrors() + .RunOn(TargetFramework.Net8_0); + } + [Fact] public async Task Escapes_namespaces() { diff --git a/tests/SnapshotTests/BsonSerializationGeneration/snapshots/snap-v8.0/BsonSerializationGenerationTests.Writes_bson_serializers_but_manually_register_the_serializers.verified.txt b/tests/SnapshotTests/BsonSerializationGeneration/snapshots/snap-v8.0/BsonSerializationGenerationTests.Writes_bson_serializers_but_manually_register_the_serializers.verified.txt new file mode 100644 index 0000000000..d21fe57a4e --- /dev/null +++ b/tests/SnapshotTests/BsonSerializationGeneration/snapshots/snap-v8.0/BsonSerializationGenerationTests.Writes_bson_serializers_but_manually_register_the_serializers.verified.txt @@ -0,0 +1,1288 @@ +[ +// ------------------------------------------------------------------------------ +// +// 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. +// +// ------------------------------------------------------------------------------ +// 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 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, CS8632 +#pragma warning disable CS8604 // Possible null reference argument. + +// Suppress warnings about CS1591: Missing XML comment for publicly visible type or member 'Type_or_Member' +#pragma warning disable CS1591 +// Suppress warnings about CS8767 : Nullability of reference types in type of parameter doesn't match implicitly implemented member (possibly because of nullability attributes). +#pragma warning disable CS8767 +namespace Whatever; +public partial class AgeBsonSerializer : global::MongoDB.Bson.Serialization.Serializers.SerializerBase +{ + private readonly global::MongoDB.Bson.Serialization.IBsonSerializer _serializer = global::MongoDB.Bson.Serialization.BsonSerializer.LookupSerializer(); + public override Whatever.Age Deserialize(global::MongoDB.Bson.Serialization.BsonDeserializationContext context, global::MongoDB.Bson.Serialization.BsonDeserializationArgs args) + { + var newArgs = new global::MongoDB.Bson.Serialization.BsonDeserializationArgs + { + NominalType = typeof(global::System.Int32) + }; + return Deserialize(_serializer.Deserialize(context, newArgs)); + } + + public override void Serialize(global::MongoDB.Bson.Serialization.BsonSerializationContext context, global::MongoDB.Bson.Serialization.BsonSerializationArgs args, Whatever.Age value) => _serializer.Serialize(context, args, value.Value); + static Whatever.Age Deserialize(global::System.Int32 value) => UnsafeDeserialize(default, value); + [global::System.Runtime.CompilerServices.UnsafeAccessor(global::System.Runtime.CompilerServices.UnsafeAccessorKind.StaticMethod, Name = "__Deserialize")] + static extern Whatever.Age UnsafeDeserialize(Whatever.Age @this, global::System.Int32 value); +} + +// ------------------------------------------------------------------------------ +// +// 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. +// +// ------------------------------------------------------------------------------ +// 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 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, CS8632 +#pragma warning disable CS8604 // Possible null reference argument. + +// Suppress warnings about CS1591: Missing XML comment for publicly visible type or member 'Type_or_Member' +#pragma warning disable CS1591 +// Suppress warnings about CS8767 : Nullability of reference types in type of parameter doesn't match implicitly implemented member (possibly because of nullability attributes). +#pragma warning disable CS8767 +namespace Whatever; +public partial class NameBsonSerializer : global::MongoDB.Bson.Serialization.Serializers.SerializerBase +{ + private readonly global::MongoDB.Bson.Serialization.IBsonSerializer _serializer = global::MongoDB.Bson.Serialization.BsonSerializer.LookupSerializer(); + public override Whatever.Name Deserialize(global::MongoDB.Bson.Serialization.BsonDeserializationContext context, global::MongoDB.Bson.Serialization.BsonDeserializationArgs args) + { + var newArgs = new global::MongoDB.Bson.Serialization.BsonDeserializationArgs + { + NominalType = typeof(global::System.String) + }; + return Deserialize(_serializer.Deserialize(context, newArgs)); + } + + public override void Serialize(global::MongoDB.Bson.Serialization.BsonSerializationContext context, global::MongoDB.Bson.Serialization.BsonSerializationArgs args, Whatever.Name value) => _serializer.Serialize(context, args, value.Value); + static Whatever.Name Deserialize(global::System.String value) => UnsafeDeserialize(default, value); + [global::System.Runtime.CompilerServices.UnsafeAccessor(global::System.Runtime.CompilerServices.UnsafeAccessorKind.StaticMethod, Name = "__Deserialize")] + static extern Whatever.Name UnsafeDeserialize(Whatever.Name @this, global::System.String value); +} + +// ------------------------------------------------------------------------------ +// +// 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. +// +// ------------------------------------------------------------------------------ +// 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 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, CS8632 +#pragma warning disable CS8604 // Possible null reference argument. + +// Suppress warnings about CS1591: Missing XML comment for publicly visible type or member 'Type_or_Member' +#pragma warning disable CS1591 +// Suppress warnings about CS8767 : Nullability of reference types in type of parameter doesn't match implicitly implemented member (possibly because of nullability attributes). +#pragma warning disable CS8767 +public static class BsonSerializationRegisterForgenerator +{ + public static void TryRegister() + { + global::MongoDB.Bson.Serialization.BsonSerializer.TryRegisterSerializer(new Whatever.AgeBsonSerializer()); + global::MongoDB.Bson.Serialization.BsonSerializer.TryRegisterSerializer(new Whatever.NameBsonSerializer()); + } +} + +// ------------------------------------------------------------------------------ +// +// 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. +// +// ------------------------------------------------------------------------------ +// 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 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, CS8632 +#pragma warning disable CS8604 // Possible null reference argument. + +// Suppress warnings about CS1591: Missing XML comment for publicly visible type or member 'Type_or_Member' +#pragma warning disable CS1591 +// Suppress warnings about CS8767 : Nullability of reference types in type of parameter doesn't match implicitly implemented member (possibly because of nullability attributes). +#pragma warning disable CS8767 +namespace generator +{ + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Vogen", "1.0.0.0")] + public class VogenTypesFactory : global::System.Text.Json.Serialization.JsonConverterFactory + { + public VogenTypesFactory() + { + } + + private static readonly global::System.Collections.Generic.Dictionary> _lookup = new global::System.Collections.Generic.Dictionary> + { + }; + public override bool CanConvert(global::System.Type typeToConvert) => _lookup.ContainsKey(typeToConvert); + public override global::System.Text.Json.Serialization.JsonConverter CreateConverter(global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) => _lookup[typeToConvert].Value; + } +} + +// ------------------------------------------------------------------------------ +// +// 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. +// +// ------------------------------------------------------------------------------ +// 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 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, CS8632 +#pragma warning disable CS8604 // Possible null reference argument. + +// Suppress warnings about CS1591: Missing XML comment for publicly visible type or member 'Type_or_Member' +#pragma warning disable CS1591 +// Suppress warnings about CS8767 : Nullability of reference types in type of parameter doesn't match implicitly implemented member (possibly because of nullability attributes). +#pragma warning disable CS8767 +namespace Whatever +{ + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Vogen", "1.0.0.0")] + [global::System.Diagnostics.DebuggerTypeProxyAttribute(typeof(AgeDebugView))] + [global::System.Diagnostics.DebuggerDisplayAttribute("Underlying type: global::System.Int32, Value = { _value }")] + // ReSharper disable once UnusedType.Global + public partial struct Age : global::System.IEquatable, global::System.IEquatable, global::System.IComparable, global::System.IComparable, global::System.IParsable, global::System.ISpanParsable, global::System.IUtf8SpanParsable, global::System.IFormattable, global::System.ISpanFormattable, global::System.IUtf8SpanFormattable, global::System.IConvertible + { +#if DEBUG +private readonly global::System.Diagnostics.StackTrace _stackTrace = null!; +#endif +#if !VOGEN_NO_VALIDATION + private readonly global::System.Boolean _isInitialized; +#endif + private readonly global::System.Int32 _value; + /// + /// Gets the underlying value if set, otherwise a is thrown. + /// + public readonly global::System.Int32 Value + { + [global::System.Diagnostics.DebuggerStepThroughAttribute] + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + get + { + EnsureInitialized(); + return _value; + } + } + + [global::System.Diagnostics.DebuggerStepThroughAttribute] + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + public Age() + { +#if DEBUG + _stackTrace = new global::System.Diagnostics.StackTrace(); +#endif +#if !VOGEN_NO_VALIDATION + _isInitialized = false; +#endif + _value = default; + } + + [global::System.Diagnostics.DebuggerStepThroughAttribute] + private Age(global::System.Int32 value) + { + _value = value; +#if !VOGEN_NO_VALIDATION + _isInitialized = true; +#endif +#if DEBUG + _stackTrace = null; +#endif + } + + /// + /// Builds an instance from the provided underlying type. + /// + /// The underlying type. + /// An instance of this type. + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + public static Age From(global::System.Int32 value) + { + return new Age(value); + } + + /// + /// Tries to build an instance from the provided underlying type. + /// If a normalization method is provided, it will be called. + /// If validation is provided, and it fails, false will be returned. + /// + /// The underlying type. + /// An instance of the value object. + /// True if the value object can be built, otherwise false. + public static bool TryFrom( +#if NETCOREAPP3_0_OR_GREATER +[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] +#endif + global::System.Int32 value, +#if NETCOREAPP3_0_OR_GREATER +[global::System.Diagnostics.CodeAnalysis.MaybeNullWhen(false)] +#endif + out Age vo) + { + vo = new Age(value); + return true; + } + + /// + /// Tries to build an instance from the provided underlying value. + /// If a normalization method is provided, it will be called. + /// If validation is provided, and it fails, an error will be returned. + /// + /// The primitive value. + /// A containing either the value object, or an error. + public static global::Vogen.ValueObjectOrError TryFrom(global::System.Int32 value) + { + return new global::Vogen.ValueObjectOrError(new Age(value)); + } + + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] +#if VOGEN_NO_VALIDATION +#pragma warning disable CS8775 + public readonly bool IsInitialized() => true; +#pragma warning restore CS8775 +#else + public readonly bool IsInitialized() => _isInitialized; +#endif + public static explicit operator Age(global::System.Int32 value) => From(value); + public static explicit operator global::System.Int32(Age value) => value.Value; + // only called internally when something has been deserialized into + // its primitive type. + private static Age __Deserialize(global::System.Int32 value) + { + return new Age(value); + } + + public readonly global::System.Boolean Equals(Age 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.Default.Equals(Value, other.Value); + } + + public global::System.Boolean Equals(Age other, global::System.Collections.Generic.IEqualityComparer comparer) + { + return comparer.Equals(this, other); + } + + public readonly global::System.Boolean Equals(global::System.Int32 primitive) + { + return Value.Equals(primitive); + } + + public readonly override global::System.Boolean Equals(global::System.Object obj) + { + return obj is Age && Equals((Age)obj); + } + + public static global::System.Boolean operator ==(Age left, Age right) => left.Equals(right); + public static global::System.Boolean operator !=(Age left, Age right) => !(left == right); + public static global::System.Boolean operator ==(Age left, global::System.Int32 right) => left.Value.Equals(right); + public static global::System.Boolean operator ==(global::System.Int32 left, Age right) => right.Value.Equals(left); + public static global::System.Boolean operator !=(global::System.Int32 left, Age right) => !(left == right); + public static global::System.Boolean operator !=(Age left, global::System.Int32 right) => !(left == right); + public int CompareTo(Age other) => Value.CompareTo(other.Value); + public int CompareTo(object other) + { + if (other is null) + return 1; + if (other is Age x) + return CompareTo(x); + ThrowHelper.ThrowArgumentException("Cannot compare to object as it is not of type Age", nameof(other)); + return 0; + } + + /// + /// + /// + /// + /// True if the value could a) be parsed by the underlying type, and b) passes any validation (after running any optional normalization). + /// + public static global::System.Boolean TryParse(global::System.ReadOnlySpan utf8Text, global::System.Globalization.NumberStyles style, global::System.IFormatProvider provider, +#if NETCOREAPP3_0_OR_GREATER +[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] +#endif + out Age result) + { + if (global::System.Int32.TryParse(utf8Text, style, provider, out var __v)) + { + result = new Age(__v); + return true; + } + + result = default; + return false; + } + + /// + /// + /// + /// + /// True if the value could a) be parsed by the underlying type, and b) passes any validation (after running any optional normalization). + /// + public static global::System.Boolean TryParse(global::System.ReadOnlySpan utf8Text, global::System.IFormatProvider provider, +#if NETCOREAPP3_0_OR_GREATER +[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] +#endif + out Age result) + { + if (global::System.Int32.TryParse(utf8Text, provider, out var __v)) + { + result = new Age(__v); + return true; + } + + result = default; + return false; + } + + /// + /// + /// + /// + /// True if the value could a) be parsed by the underlying type, and b) passes any validation (after running any optional normalization). + /// + public static global::System.Boolean TryParse(global::System.ReadOnlySpan utf8Text, +#if NETCOREAPP3_0_OR_GREATER +[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] +#endif + out Age result) + { + if (global::System.Int32.TryParse(utf8Text, out var __v)) + { + result = new Age(__v); + return true; + } + + result = default; + return false; + } + + /// + /// + /// + /// + /// True if the value could a) be parsed by the underlying type, and b) passes any validation (after running any optional normalization). + /// + public static global::System.Boolean TryParse(global::System.ReadOnlySpan s, global::System.Globalization.NumberStyles style, global::System.IFormatProvider provider, +#if NETCOREAPP3_0_OR_GREATER +[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] +#endif + out Age result) + { + if (global::System.Int32.TryParse(s, style, provider, out var __v)) + { + result = new Age(__v); + return true; + } + + result = default; + return false; + } + + /// + /// + /// + /// + /// True if the value could a) be parsed by the underlying type, and b) passes any validation (after running any optional normalization). + /// + public static global::System.Boolean TryParse(global::System.ReadOnlySpan s, global::System.IFormatProvider provider, +#if NETCOREAPP3_0_OR_GREATER +[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] +#endif + out Age result) + { + if (global::System.Int32.TryParse(s, provider, out var __v)) + { + result = new Age(__v); + return true; + } + + result = default; + return false; + } + + /// + /// + /// + /// + /// True if the value could a) be parsed by the underlying type, and b) passes any validation (after running any optional normalization). + /// + public static global::System.Boolean TryParse(global::System.ReadOnlySpan s, +#if NETCOREAPP3_0_OR_GREATER +[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] +#endif + out Age result) + { + if (global::System.Int32.TryParse(s, out var __v)) + { + result = new Age(__v); + return true; + } + + result = default; + return false; + } + + /// + /// + /// + /// + /// True if the value could a) be parsed by the underlying type, and b) passes any validation (after running any optional normalization). + /// + 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 Age result) + { + if (global::System.Int32.TryParse(s, style, provider, out var __v)) + { + result = new Age(__v); + return true; + } + + result = default; + return false; + } + + /// + /// + /// + /// + /// True if the value could a) be parsed by the underlying type, and b) passes any validation (after running any optional normalization). + /// + 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 Age result) + { + if (global::System.Int32.TryParse(s, provider, out var __v)) + { + result = new Age(__v); + return true; + } + + result = default; + return false; + } + + /// + /// + /// + /// + /// True if the value could a) be parsed by the underlying type, and b) passes any validation (after running any optional normalization). + /// + public static global::System.Boolean TryParse(string s, +#if NETCOREAPP3_0_OR_GREATER +[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] +#endif + out Age result) + { + if (global::System.Int32.TryParse(s, out var __v)) + { + result = new Age(__v); + return true; + } + + result = default; + return false; + } + + /// + /// + /// + /// + /// The value created by calling the Parse method on the primitive. + /// + /// Thrown when the value can be parsed, but is not valid. + public static Age Parse(global::System.ReadOnlySpan utf8Text, global::System.Globalization.NumberStyles style, global::System.IFormatProvider provider) + { + var r = global::System.Int32.Parse(utf8Text, style, provider); + return From(r); + } + + /// + /// + /// + /// + /// The value created by calling the Parse method on the primitive. + /// + /// Thrown when the value can be parsed, but is not valid. + public static Age Parse(global::System.ReadOnlySpan utf8Text, global::System.IFormatProvider provider) + { + var r = global::System.Int32.Parse(utf8Text, provider); + return From(r); + } + + /// + /// + /// + /// + /// The value created by calling the Parse method on the primitive. + /// + /// Thrown when the value can be parsed, but is not valid. + public static Age Parse(global::System.ReadOnlySpan s, global::System.Globalization.NumberStyles style, global::System.IFormatProvider provider) + { + var r = global::System.Int32.Parse(s, style, provider); + return From(r); + } + + /// + /// + /// + /// + /// The value created by calling the Parse method on the primitive. + /// + /// Thrown when the value can be parsed, but is not valid. + public static Age Parse(global::System.ReadOnlySpan s, global::System.IFormatProvider provider) + { + var r = global::System.Int32.Parse(s, provider); + return From(r); + } + + /// + /// + /// + /// + /// The value created by calling the Parse method on the primitive. + /// + /// Thrown when the value can be parsed, but is not valid. + public static Age Parse(string s) + { + var r = global::System.Int32.Parse(s); + return From(r); + } + + /// + /// + /// + /// + /// The value created by calling the Parse method on the primitive. + /// + /// Thrown when the value can be parsed, but is not valid. + public static Age Parse(string s, global::System.Globalization.NumberStyles style) + { + var r = global::System.Int32.Parse(s, style); + return From(r); + } + + /// + /// + /// + /// + /// The value created by calling the Parse method on the primitive. + /// + /// Thrown when the value can be parsed, but is not valid. + public static Age Parse(string s, global::System.Globalization.NumberStyles style, global::System.IFormatProvider provider) + { + var r = global::System.Int32.Parse(s, style, provider); + return From(r); + } + + /// + /// + /// + /// + /// The value created by calling the Parse method on the primitive. + /// + /// Thrown when the value can be parsed, but is not valid. + public static Age Parse(string s, global::System.IFormatProvider provider) + { + var r = global::System.Int32.Parse(s, provider); + return From(r); + } + +#nullable disable + /// + public string ToString([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("NumericFormat")] string format, global::System.IFormatProvider provider) + { + return IsInitialized() ? Value.ToString(format, provider) : "[UNINITIALIZED]"; + } + + /// + public bool TryFormat(global::System.Span destination, out int charsWritten, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("NumericFormat")] global::System.ReadOnlySpan format, global::System.IFormatProvider provider) + { + charsWritten = default; + return IsInitialized() ? Value.TryFormat(destination, out charsWritten, format, provider) : true; + } + + /// + public bool TryFormat(global::System.Span utf8Destination, out int bytesWritten, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("NumericFormat")] global::System.ReadOnlySpan format, global::System.IFormatProvider provider) + { + bytesWritten = default; + return IsInitialized() ? Value.TryFormat(utf8Destination, out bytesWritten, format, provider) : true; + } + +#nullable restore +#nullable disable + /// + public System.TypeCode GetTypeCode() + { + return IsInitialized() ? Value.GetTypeCode() : default; + } + + /// + bool System.IConvertible.ToBoolean(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToBoolean(provider) : default; + } + + /// + byte System.IConvertible.ToByte(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToByte(provider) : default; + } + + /// + char System.IConvertible.ToChar(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToChar(provider) : default; + } + + /// + System.DateTime System.IConvertible.ToDateTime(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToDateTime(provider) : default; + } + + /// + decimal System.IConvertible.ToDecimal(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToDecimal(provider) : default; + } + + /// + double System.IConvertible.ToDouble(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToDouble(provider) : default; + } + + /// + short System.IConvertible.ToInt16(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToInt16(provider) : default; + } + + /// + int System.IConvertible.ToInt32(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToInt32(provider) : default; + } + + /// + long System.IConvertible.ToInt64(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToInt64(provider) : default; + } + + /// + sbyte System.IConvertible.ToSByte(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToSByte(provider) : default; + } + + /// + float System.IConvertible.ToSingle(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToSingle(provider) : default; + } + + /// + object System.IConvertible.ToType(global::System.Type @type, global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToType(@type, provider) : default; + } + + /// + ushort System.IConvertible.ToUInt16(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToUInt16(provider) : default; + } + + /// + uint System.IConvertible.ToUInt32(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToUInt32(provider) : default; + } + + /// + ulong System.IConvertible.ToUInt64(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToUInt64(provider) : default; + } + +#nullable restore + public readonly override global::System.Int32 GetHashCode() + { + return global::System.Collections.Generic.EqualityComparer.Default.GetHashCode(Value); + } + + /// + public override global::System.String ToString() => IsInitialized() ? Value.ToString() ?? "" : "[UNINITIALIZED]"; + /// + public global::System.String ToString(global::System.IFormatProvider provider) => IsInitialized() ? Value.ToString(provider) ?? "" : "[UNINITIALIZED]"; + /// + public global::System.String ToString([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("NumericFormat")] string format) => IsInitialized() ? Value.ToString(format) ?? "" : "[UNINITIALIZED]"; + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + private readonly void EnsureInitialized() + { + if (!IsInitialized()) + { +#if DEBUG + ThrowHelper.ThrowWhenNotInitialized(_stackTrace); +#else + ThrowHelper.ThrowWhenNotInitialized(); +#endif + } + } + +#nullable disable + internal sealed class AgeDebugView + { + private readonly Age _t; + AgeDebugView(Age 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 => @"Bson"; + } + +#nullable restore + static class ThrowHelper + { +#if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute] +#endif + internal static void ThrowInvalidOperationException(string message) => throw new global::System.InvalidOperationException(message); +#if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute] +#endif + internal static void ThrowArgumentException(string message, string arg) => throw new global::System.ArgumentException(message, arg); +#if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute] +#endif + internal static void ThrowWhenCreatedWithNull() => throw CreateCannotBeNullException(); +#if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute] +#endif + internal static void ThrowWhenNotInitialized() => throw CreateValidationException("Use of uninitialized Value Object."); +#if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute] +#endif + internal static void ThrowWhenNotInitialized(global::System.Diagnostics.StackTrace stackTrace) => throw CreateValidationException("Use of uninitialized Value Object at: " + stackTrace ?? ""); +#if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute] +#endif + internal static void ThrowWhenValidationFails(global::Vogen.Validation validation) + { + throw CreateValidationException(validation); + } + + internal static global::System.Exception CreateValidationException(string message) => new global::Vogen.ValueObjectValidationException(message); + internal static global::System.Exception CreateCannotBeNullException() => new global::Vogen.ValueObjectValidationException("Cannot create a value object with null."); + internal static global::System.Exception CreateValidationException(global::Vogen.Validation validation) + { + var ex = CreateValidationException(validation.ErrorMessage); + if (validation.Data != null) + { + foreach (var kvp in validation.Data) + { + ex.Data[kvp.Key] = kvp.Value; + } + } + + return ex; + } + } + } +} + +// ------------------------------------------------------------------------------ +// +// 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. +// +// ------------------------------------------------------------------------------ +// 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 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, CS8632 +#pragma warning disable CS8604 // Possible null reference argument. + +// Suppress warnings about CS1591: Missing XML comment for publicly visible type or member 'Type_or_Member' +#pragma warning disable CS1591 +// Suppress warnings about CS8767 : Nullability of reference types in type of parameter doesn't match implicitly implemented member (possibly because of nullability attributes). +#pragma warning disable CS8767 +namespace Whatever +{ + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Vogen", "1.0.0.0")] + [global::System.Diagnostics.DebuggerTypeProxyAttribute(typeof(NameDebugView))] + [global::System.Diagnostics.DebuggerDisplayAttribute("Underlying type: global::System.String, Value = { _value }")] + // ReSharper disable once UnusedType.Global + public partial struct Name : global::System.IEquatable, global::System.IEquatable, global::System.IComparable, global::System.IComparable, global::System.IParsable, global::System.IConvertible + { +#if DEBUG +private readonly global::System.Diagnostics.StackTrace _stackTrace = null!; +#endif +#if !VOGEN_NO_VALIDATION + private readonly global::System.Boolean _isInitialized; +#endif + private readonly global::System.String _value; + /// + /// Gets the underlying value if set, otherwise a is thrown. + /// + public readonly global::System.String Value + { + [global::System.Diagnostics.DebuggerStepThroughAttribute] + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + get + { + EnsureInitialized(); + return _value; + } + } + + [global::System.Diagnostics.DebuggerStepThroughAttribute] + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + public Name() + { +#if DEBUG + _stackTrace = new global::System.Diagnostics.StackTrace(); +#endif +#if !VOGEN_NO_VALIDATION + _isInitialized = false; +#endif + _value = default; + } + + [global::System.Diagnostics.DebuggerStepThroughAttribute] + private Name(global::System.String value) + { + _value = value; +#if !VOGEN_NO_VALIDATION + _isInitialized = true; +#endif +#if DEBUG + _stackTrace = null; +#endif + } + + /// + /// Builds an instance from the provided underlying type. + /// + /// The underlying type. + /// An instance of this type. + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + public static Name From(global::System.String value) + { + if (value is null) + { + ThrowHelper.ThrowWhenCreatedWithNull(); + return default !; + } + + return new Name(value); + } + + /// + /// Tries to build an instance from the provided underlying type. + /// If a normalization method is provided, it will be called. + /// If validation is provided, and it fails, false will be returned. + /// + /// The underlying type. + /// An instance of the value object. + /// True if the value object can be built, otherwise false. + public static bool TryFrom( +#if NETCOREAPP3_0_OR_GREATER +[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] +#endif + global::System.String value, +#if NETCOREAPP3_0_OR_GREATER +[global::System.Diagnostics.CodeAnalysis.MaybeNullWhen(false)] +#endif + out Name vo) + { + if (value is null) + { + vo = default; + return false; + } + + vo = new Name(value); + return true; + } + + /// + /// Tries to build an instance from the provided underlying value. + /// If a normalization method is provided, it will be called. + /// If validation is provided, and it fails, an error will be returned. + /// + /// The primitive value. + /// A containing either the value object, or an error. + public static global::Vogen.ValueObjectOrError TryFrom(global::System.String value) + { + if (value is null) + { + return new global::Vogen.ValueObjectOrError(global::Vogen.Validation.Invalid("The value provided was null")); + } + + return new global::Vogen.ValueObjectOrError(new Name(value)); + } + + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] +#if VOGEN_NO_VALIDATION +#pragma warning disable CS8775 + public readonly bool IsInitialized() => true; +#pragma warning restore CS8775 +#else + public readonly bool IsInitialized() => _isInitialized; +#endif + public static explicit operator Name(global::System.String value) => From(value); + public static explicit operator global::System.String(Name value) => value.Value; + // only called internally when something has been deserialized into + // its primitive type. + private static Name __Deserialize(global::System.String value) + { + if (value is null) + { + ThrowHelper.ThrowWhenCreatedWithNull(); + return default !; + } + + return new Name(value); + } + + public readonly global::System.Boolean Equals(Name 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.Default.Equals(Value, other.Value); + } + + public global::System.Boolean Equals(Name other, global::System.Collections.Generic.IEqualityComparer comparer) + { + return comparer.Equals(this, other); + } + + public readonly global::System.Boolean Equals(global::System.String primitive) + { + return Value.Equals(primitive); + } + + public readonly global::System.Boolean Equals(global::System.String primitive, global::System.StringComparer comparer) + { + return comparer.Equals(Value, primitive); + } + + public readonly override global::System.Boolean Equals(global::System.Object obj) + { + return obj is Name && Equals((Name)obj); + } + + public static global::System.Boolean operator ==(Name left, Name right) => left.Equals(right); + public static global::System.Boolean operator !=(Name left, Name right) => !(left == right); + public static global::System.Boolean operator ==(Name left, global::System.String right) => left.Value.Equals(right); + public static global::System.Boolean operator ==(global::System.String left, Name right) => right.Value.Equals(left); + public static global::System.Boolean operator !=(global::System.String left, Name right) => !(left == right); + public static global::System.Boolean operator !=(Name left, global::System.String right) => !(left == right); + public int CompareTo(Name other) => Value.CompareTo(other.Value); + public int CompareTo(object other) + { + if (other is null) + return 1; + if (other is Name x) + return CompareTo(x); + ThrowHelper.ThrowArgumentException("Cannot compare to object as it is not of type Name", nameof(other)); + return 0; + } + + /// + /// + /// + /// True if the value passes any validation (after running any optional normalization). + /// + public static global::System.Boolean TryParse( +#if NETCOREAPP3_0_OR_GREATER +[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] +#endif + global::System.String s, global::System.IFormatProvider provider, +#if NETCOREAPP3_0_OR_GREATER +[global::System.Diagnostics.CodeAnalysis.MaybeNullWhen(false)] +#endif + out Name result) + { + if (s is null) + { + result = default; + return false; + } + + result = new Name(s); + return true; + } + + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static Name Parse(global::System.String s, global::System.IFormatProvider provider) + { + return From(s); + } + +#nullable disable +#nullable restore +#nullable disable + /// + public System.TypeCode GetTypeCode() + { + return IsInitialized() ? Value.GetTypeCode() : default; + } + + /// + bool System.IConvertible.ToBoolean(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToBoolean(provider) : default; + } + + /// + byte System.IConvertible.ToByte(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToByte(provider) : default; + } + + /// + char System.IConvertible.ToChar(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToChar(provider) : default; + } + + /// + System.DateTime System.IConvertible.ToDateTime(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToDateTime(provider) : default; + } + + /// + decimal System.IConvertible.ToDecimal(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToDecimal(provider) : default; + } + + /// + double System.IConvertible.ToDouble(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToDouble(provider) : default; + } + + /// + short System.IConvertible.ToInt16(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToInt16(provider) : default; + } + + /// + int System.IConvertible.ToInt32(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToInt32(provider) : default; + } + + /// + long System.IConvertible.ToInt64(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToInt64(provider) : default; + } + + /// + sbyte System.IConvertible.ToSByte(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToSByte(provider) : default; + } + + /// + float System.IConvertible.ToSingle(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToSingle(provider) : default; + } + + /// + object System.IConvertible.ToType(global::System.Type @type, global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToType(@type, provider) : default; + } + + /// + ushort System.IConvertible.ToUInt16(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToUInt16(provider) : default; + } + + /// + uint System.IConvertible.ToUInt32(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToUInt32(provider) : default; + } + + /// + ulong System.IConvertible.ToUInt64(global::System.IFormatProvider provider) + { + return IsInitialized() ? (Value as System.IConvertible).ToUInt64(provider) : default; + } + +#nullable restore + public readonly override global::System.Int32 GetHashCode() + { + return global::System.Collections.Generic.EqualityComparer.Default.GetHashCode(Value); + } + + /// + public override global::System.String ToString() => IsInitialized() ? Value.ToString() ?? "" : "[UNINITIALIZED]"; + /// + public global::System.String ToString(global::System.IFormatProvider provider) => IsInitialized() ? Value.ToString(provider) ?? "" : "[UNINITIALIZED]"; + [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + private readonly void EnsureInitialized() + { + if (!IsInitialized()) + { +#if DEBUG + ThrowHelper.ThrowWhenNotInitialized(_stackTrace); +#else + ThrowHelper.ThrowWhenNotInitialized(); +#endif + } + } + +#nullable disable + internal sealed class NameDebugView + { + private readonly Name _t; + NameDebugView(Name t) + { + _t = t; + } + + public global::System.Boolean IsInitialized => _t.IsInitialized(); + public global::System.String UnderlyingType => "System.String"; + 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 => @"Bson"; + } + +#nullable restore + static class ThrowHelper + { +#if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute] +#endif + internal static void ThrowInvalidOperationException(string message) => throw new global::System.InvalidOperationException(message); +#if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute] +#endif + internal static void ThrowArgumentException(string message, string arg) => throw new global::System.ArgumentException(message, arg); +#if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute] +#endif + internal static void ThrowWhenCreatedWithNull() => throw CreateCannotBeNullException(); +#if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute] +#endif + internal static void ThrowWhenNotInitialized() => throw CreateValidationException("Use of uninitialized Value Object."); +#if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute] +#endif + internal static void ThrowWhenNotInitialized(global::System.Diagnostics.StackTrace stackTrace) => throw CreateValidationException("Use of uninitialized Value Object at: " + stackTrace ?? ""); +#if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute] +#endif + internal static void ThrowWhenValidationFails(global::Vogen.Validation validation) + { + throw CreateValidationException(validation); + } + + internal static global::System.Exception CreateValidationException(string message) => new global::Vogen.ValueObjectValidationException(message); + internal static global::System.Exception CreateCannotBeNullException() => new global::Vogen.ValueObjectValidationException("Cannot create a value object with null."); + internal static global::System.Exception CreateValidationException(global::Vogen.Validation validation) + { + var ex = CreateValidationException(validation.ErrorMessage); + if (validation.Data != null) + { + foreach (var kvp in validation.Data) + { + ex.Data[kvp.Key] = kvp.Value; + } + } + + return ex; + } + } + } +} +] \ No newline at end of file