From cf475cdedbfc63fc2dab2263cb1bb0414285236a Mon Sep 17 00:00:00 2001 From: Steve Dunn Date: Fri, 3 May 2024 05:57:19 +0100 Subject: [PATCH 1/2] Added tests and examples --- src/Vogen/AnalyzerReleases.Unshipped.md | 1 + src/Vogen/Diagnostics/RuleIdentifiers.cs | 1 + src/Vogen/Rules/DoNotUseNewAnalyzer.cs | 52 +++++++++++++++++++++++- 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/Vogen/AnalyzerReleases.Unshipped.md b/src/Vogen/AnalyzerReleases.Unshipped.md index cc67b67f30..3b2ae45ced 100644 --- a/src/Vogen/AnalyzerReleases.Unshipped.md +++ b/src/Vogen/AnalyzerReleases.Unshipped.md @@ -5,3 +5,4 @@ Rule ID | Category | Severity | Notes --------|----------|----------|------- +VOG027 | Usage | Error | DoNotUseNewAnalyzer diff --git a/src/Vogen/Diagnostics/RuleIdentifiers.cs b/src/Vogen/Diagnostics/RuleIdentifiers.cs index 9b8a19aa8e..7644dcf104 100644 --- a/src/Vogen/Diagnostics/RuleIdentifiers.cs +++ b/src/Vogen/Diagnostics/RuleIdentifiers.cs @@ -29,4 +29,5 @@ public static class RuleIdentifiers public const string DuplicateTypesFound = "VOG024"; public const string DoNotUseReflection = "VOG025"; public const string DoNotDeriveFromVogenAttributes = "VOG026"; + public const string IncorrectUseOfInstanceField = "VOG027"; } \ No newline at end of file diff --git a/src/Vogen/Rules/DoNotUseNewAnalyzer.cs b/src/Vogen/Rules/DoNotUseNewAnalyzer.cs index a935ebff77..c54d5e984b 100644 --- a/src/Vogen/Rules/DoNotUseNewAnalyzer.cs +++ b/src/Vogen/Rules/DoNotUseNewAnalyzer.cs @@ -22,7 +22,18 @@ public class DoNotUseNewAnalyzer : DiagnosticAnalyzer description: "The value object is created with a new expression. This can lead to invalid value objects in your domain. Use the From method instead."); - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(_rule); + private static readonly DiagnosticDescriptor _rule2 = new DiagnosticDescriptor( + RuleIdentifiers.IncorrectUseOfInstanceField, + "Instance fields should be declared as public and static", + "Type '{0}' cannot be constructed as a field with 'new' as it should be public and static", + RuleCategories.Usage, + DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: + "The value object is created with a new expression. This can lead to invalid value objects in your domain. Use the From method instead."); + + public override ImmutableArray SupportedDiagnostics => + ImmutableArray.Create(_rule, _rule2); public override void Initialize(AnalysisContext context) { @@ -43,9 +54,48 @@ private static void AnalyzeExpression(OperationAnalysisContext context) if (c.Type is not INamedTypeSymbol symbol) return; if (!VoFilter.IsTarget(symbol)) return; + + var instanceFieldState = IsAPublicStaticFieldInAValueObject(); + + if (instanceFieldState == InstanceField.NotValid) + { + context.ReportDiagnostic(DiagnosticsCatalogue.BuildDiagnostic(_rule2, symbol.Name, context.Operation.Syntax.GetLocation())); + + return; + } + if (instanceFieldState == InstanceField.Valid) return; + var diagnostic = DiagnosticsCatalogue.BuildDiagnostic(_rule, symbol.Name, context.Operation.Syntax.GetLocation()); context.ReportDiagnostic(diagnostic); + + return; + + InstanceField IsAPublicStaticFieldInAValueObject() + { + var cs = context.ContainingSymbol as IFieldSymbol; + if (cs is null) return InstanceField.NotApplicable; + var type = cs.ContainingType; + var isVo = VoFilter.IsTarget(type); + if (!isVo) + { + return InstanceField.NotApplicable; + } + + if (cs.DeclaredAccessibility != Accessibility.Public) return InstanceField.NotValid; + if (!cs.IsStatic) return InstanceField.NotValid; + + return InstanceField.Valid; + } + + } + + internal enum InstanceField + { + Valid, + NotValid, + NotApplicable + } } \ No newline at end of file From 845ca3564c5b10924a15fedc85b11bffe95e8858 Mon Sep 17 00:00:00 2001 From: Steve Dunn Date: Fri, 3 May 2024 06:41:57 +0100 Subject: [PATCH 2/2] Added tests and examples --- tests/AnalyzerTests/AnalyzerTests.csproj | 1 + .../AnalyzerTests/DoNotUseNewAnalyzerTests.cs | 163 ++++- tests/AnalyzerTests/TestRunner.cs | 2 +- tests/ConsumerTests/Instances/Types.cs | 13 + tests/Shared/ProjectBuilder.cs | 2 +- .../InstanceFieldGenerationTests.cs | 21 + ...ewed_up_in_the_wrapper_itself.verified.txt | 444 +++++++++++++ ...ewed_up_in_the_wrapper_itself.verified.txt | 388 ++++++++++++ ...ewed_up_in_the_wrapper_itself.verified.txt | 388 ++++++++++++ ...ewed_up_in_the_wrapper_itself.verified.txt | 444 +++++++++++++ ...ewed_up_in_the_wrapper_itself.verified.txt | 444 +++++++++++++ ...ewed_up_in_the_wrapper_itself.verified.txt | 500 +++++++++++++++ ...ewed_up_in_the_wrapper_itself.verified.txt | 590 ++++++++++++++++++ tests/SnapshotTests/SnapshotRunner.cs | 2 +- 14 files changed, 3375 insertions(+), 27 deletions(-) create mode 100644 tests/SnapshotTests/InstanceFields/snapshots/snap-v3.1/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt create mode 100644 tests/SnapshotTests/InstanceFields/snapshots/snap-v4.6.1/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt create mode 100644 tests/SnapshotTests/InstanceFields/snapshots/snap-v4.8/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt create mode 100644 tests/SnapshotTests/InstanceFields/snapshots/snap-v5.0/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt create mode 100644 tests/SnapshotTests/InstanceFields/snapshots/snap-v6.0/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt create mode 100644 tests/SnapshotTests/InstanceFields/snapshots/snap-v7.0/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt create mode 100644 tests/SnapshotTests/InstanceFields/snapshots/snap-v8.0/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt diff --git a/tests/AnalyzerTests/AnalyzerTests.csproj b/tests/AnalyzerTests/AnalyzerTests.csproj index ba46f55259..5101dd83e2 100644 --- a/tests/AnalyzerTests/AnalyzerTests.csproj +++ b/tests/AnalyzerTests/AnalyzerTests.csproj @@ -42,6 +42,7 @@ + diff --git a/tests/AnalyzerTests/DoNotUseNewAnalyzerTests.cs b/tests/AnalyzerTests/DoNotUseNewAnalyzerTests.cs index 55851cd470..74f15d81b5 100644 --- a/tests/AnalyzerTests/DoNotUseNewAnalyzerTests.cs +++ b/tests/AnalyzerTests/DoNotUseNewAnalyzerTests.cs @@ -1,9 +1,14 @@ using System.Collections; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; +using System.Text.RegularExpressions; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Testing; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Shared; +using Vogen; using VerifyCS = AnalyzerTests.Verifiers.CSharpAnalyzerVerifier; // ReSharper disable CoVariantArrayConversion @@ -11,16 +16,31 @@ namespace AnalyzerTests { public class DoNotUseNewAnalyzerTests { + // A pattern for 'placeholders' for errors. These are stripped out when running tests + // that require both the user source and generated source. + private static readonly Regex _placeholderPattern = new(@"{\|#\d+:", RegexOptions.Compiled); + private class Types : IEnumerable { public IEnumerator GetEnumerator() { - yield return new[] {"partial class"}; - yield return new[] {"partial struct"}; - yield return new[] {"readonly partial struct"}; - yield return new[] {"partial record class"}; - yield return new[] {"partial record struct"}; - yield return new[] {"readonly partial record struct"}; + yield return ["partial class"]; + yield return ["partial struct"]; + yield return ["readonly partial struct"]; + yield return ["partial record class"]; + yield return ["partial record struct"]; + yield return ["readonly partial record struct"]; + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + } + + private class Classes : IEnumerable + { + public IEnumerator GetEnumerator() + { + yield return ["partial class"]; + yield return ["partial record class"]; } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); @@ -104,26 +124,119 @@ await Run( [ClassData(typeof(Types))] public async Task Disallow_new_from_local_function(string type) { - var source = $@" -using Vogen; -namespace Whatever; + var source = $$""" -[ValueObject] -public {type} MyVo {{ }} + using Vogen; + namespace Whatever; -public class Test {{ - public Test() {{ - MyVo Get() => {{|#0:new MyVo()|}}; - MyVo Get2() => {{|#1:new()|}}; - }} -}} -"; + [ValueObject] + public {{type}} MyVo { } + + public class Test { + public Test() { + MyVo Get() => {|#0:new MyVo()|}; + MyVo Get2() => {|#1:new()|}; + } + } + + """; await Run( source, WithDiagnostics("VOG010", DiagnosticSeverity.Error, "MyVo", 0, 1)); } + [Theory] + [ClassData(typeof(Types))] + public async Task Allow_as_public_static_field_in_a_VO(string type) + { + var userSource = $$""" + + using Vogen; + namespace Whatever + { + [ValueObject] + public {{type}} MyVo { + public static MyVo Unspecified = new MyVo(-1); + } + } + + """; + string[] sources = CombineUserAndGeneratedSource(userSource); + + await Run(sources, Enumerable.Empty()); + } + + [Theory] + [ClassData(typeof(Types))] + public async Task Disallow_as_private_static_field_in_a_VO(string type) + { + var userSource = $$""" + + using Vogen; + namespace Whatever + { + [ValueObject] + public {{type}} MyVo { + private static MyVo Unspecified1 = {|#0:new MyVo(-1)|}; + private static MyVo Unspecified2 = {|#1:new(-1)|}; + } + } + + """; + + string[] sources = CombineUserAndGeneratedSource(userSource); + + await Run(sources, WithDiagnostics("VOG027", DiagnosticSeverity.Error, "MyVo", 0, 1)); + } + + [Theory] + [ClassData(typeof(Classes))] + public async Task Disallow_as_non_static_field_in_a_VO(string type) + { + var userSource = $$""" + + using Vogen; + namespace Whatever + { + [ValueObject] + public {{type}} MyVo { + public MyVo Unspecified1 = {|#0:new MyVo(-1)|}; + public MyVo Unspecified2 = {|#1:new(-1)|}; + } + } + + """; + + string[] sources = CombineUserAndGeneratedSource(userSource); + + await Run(sources, WithDiagnostics("VOG027", DiagnosticSeverity.Error, "MyVo", 0, 1)); + } + + private static string[] CombineUserAndGeneratedSource(string userSource) + { + var r = MetadataReference.CreateFromFile(typeof(ValueObjectAttribute).Assembly.Location); + + var strippedSource = _placeholderPattern.Replace(userSource, string.Empty).Replace("|}", string.Empty); + + (ImmutableArray Diagnostics, string GeneratedSource) output = new ProjectBuilder() + .WithSource(strippedSource) + .WithTargetFramework(TargetFramework.Net8_0) + .GetGeneratedOutput(true, r); + + if (output.Diagnostics.Length > 0) + { + throw new AssertFailedException( + $""" + Expected user source to be error and generated code to be free from errors: + User source: {userSource} + Errors: {string.Join(",", output.Diagnostics.Select(d => d.ToString()))} + """); + } + + return [userSource, output.GeneratedSource]; + } + [Theory] [ClassData(typeof(Types))] public async Task Disallow_new_from_func(string type) @@ -189,19 +302,21 @@ private static IEnumerable WithDiagnostics(string code, Diagno } } - private async Task Run(string source, IEnumerable expected) + private async Task Run(string source, IEnumerable expected) => await Run([source], expected); + + private async Task Run(string[] sources, IEnumerable expected) { var test = new VerifyCS.Test { - TestState = - { - Sources = { source }, - }, - CompilerDiagnostics = CompilerDiagnostics.Errors, ReferenceAssemblies = References.Net80AndOurs.Value, }; + foreach (var eachSource in sources) + { + test.TestState.Sources.Add(eachSource); + } + test.ExpectedDiagnostics.AddRange(expected); await test.RunAsync(); diff --git a/tests/AnalyzerTests/TestRunner.cs b/tests/AnalyzerTests/TestRunner.cs index 39294fe996..cff3f27550 100644 --- a/tests/AnalyzerTests/TestRunner.cs +++ b/tests/AnalyzerTests/TestRunner.cs @@ -76,7 +76,7 @@ private void RunOn(bool ignoreInitialCompilationErrors, } } - private static (ImmutableArray Diagnostics, string Output) GetGeneratedOutput( + private static (ImmutableArray Diagnostics, string GeneratedSource) GetGeneratedOutput( string source, TargetFramework targetFramework, bool ignoreInitialCompilationErrors) diff --git a/tests/ConsumerTests/Instances/Types.cs b/tests/ConsumerTests/Instances/Types.cs index 93d51a4188..41c5158187 100644 --- a/tests/ConsumerTests/Instances/Types.cs +++ b/tests/ConsumerTests/Instances/Types.cs @@ -1,5 +1,18 @@ namespace ConsumerTests.Instances; +[ValueObject] +public partial class IntWithNewedUpInstanceFields +{ + public static IntWithNewedUpInstanceFields Invalid = new(-1); + public static IntWithNewedUpInstanceFields Unspecified = new(-2); + + // Error VOG027 : Type 'IntWithNewedUpInstanceFields' cannot be constructed as a field with 'new' as it should be public and static + // public IntWithNewedUpInstanceFields NotStatic = new(-2); + + // Error VOG027 : Type 'IntWithNewedUpInstanceFields' cannot be constructed as a field with 'new' as it should be public and static + // internal static IntWithNewedUpInstanceFields NotPublic = new(-2); +} + [ValueObject(typeof(int))] [Instance(name: "Invalid", value: -1)] [Instance(name: "Unspecified", value: -2)] diff --git a/tests/Shared/ProjectBuilder.cs b/tests/Shared/ProjectBuilder.cs index 6a287a2496..21ece9e5f8 100644 --- a/tests/Shared/ProjectBuilder.cs +++ b/tests/Shared/ProjectBuilder.cs @@ -210,7 +210,7 @@ public ProjectBuilder WithNugetPackages(IEnumerable packages) return this; } - public (ImmutableArray Diagnostics, string Output) GetGeneratedOutput( + public (ImmutableArray Diagnostics, string GeneratedSource) GetGeneratedOutput( bool ignoreInitialCompilationErrors, MetadataReference? valueObjectAttributeMetadata = null) where T : IIncrementalGenerator, new() diff --git a/tests/SnapshotTests/InstanceFields/InstanceFieldGenerationTests.cs b/tests/SnapshotTests/InstanceFields/InstanceFieldGenerationTests.cs index cd258301b0..432b8bec1e 100644 --- a/tests/SnapshotTests/InstanceFields/InstanceFieldGenerationTests.cs +++ b/tests/SnapshotTests/InstanceFields/InstanceFieldGenerationTests.cs @@ -1,6 +1,7 @@ using System.Collections; using System.Collections.Generic; using System.Threading.Tasks; +using Shared; using VerifyXunit; using Vogen; @@ -29,6 +30,26 @@ public partial struct BooleanThing .RunOnAllFrameworks(); } + [Fact] + public Task Instances_can_be_newed_up_in_the_wrapper_itself() + { + var source = $$""" + using Vogen; + namespace Whatever; + + [ValueObject(typeof(int))] + public partial class MyVo + { + public static readonly MyVo Unspecified = new MyVo(-1); + } + + """; + return new SnapshotRunner() + .WithSource(source) + .IgnoreInitialCompilationErrors() + .RunOnAllFrameworks(); + } + [Fact] public Task Instance_names_can_have_reserved_keywords() { diff --git a/tests/SnapshotTests/InstanceFields/snapshots/snap-v3.1/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt b/tests/SnapshotTests/InstanceFields/snapshots/snap-v3.1/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt new file mode 100644 index 0000000000..87eef397f8 --- /dev/null +++ b/tests/SnapshotTests/InstanceFields/snapshots/snap-v3.1/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt @@ -0,0 +1,444 @@ +// ------------------------------------------------------------------------------ +// +// 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 + +// Suppress warnings about CS1591: Missing XML comment for publicly visible type or member 'Type_or_Member' +#pragma warning disable CS1591 + +using Vogen; + +namespace Whatever +{ + + [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.Int32, Value = { _value }")] + public partial class MyVo : global::System.IEquatable, global::System.IEquatable , global::System.IComparable, global::System.IComparable + { +#if DEBUG + private readonly global::System.Diagnostics.StackTrace _stackTrace = null; +#endif + private readonly global::System.Boolean _isInitialized; + private readonly System.Int32 _value; + +/// +/// Gets the underlying value if set, otherwise a is thrown. +/// +public System.Int32 Value + { + [global::System.Diagnostics.DebuggerStepThroughAttribute] + get + { + EnsureInitialized(); + return _value; + } + } + + + [global::System.Diagnostics.DebuggerStepThroughAttribute] + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + public MyVo() + { +#if DEBUG + _stackTrace = new global::System.Diagnostics.StackTrace(); +#endif + _isInitialized = false; + _value = default; + } + + [global::System.Diagnostics.DebuggerStepThroughAttribute] + private MyVo(System.Int32 value) + { + _value = value; + _isInitialized = true; + } + + /// + /// Builds an instance from the provided underlying type. + /// + /// The underlying type. + /// An instance of this type. + public static MyVo From(System.Int32 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.Int32 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.Default.Equals(Value, other.Value); + } + public global::System.Boolean Equals(MyVo other, global::System.Collections.Generic.IEqualityComparer comparer) + { + return comparer.Equals(this, other); + } + + + public global::System.Boolean Equals(System.Int32 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.Int32 right) => Equals(left.Value, right); + public static global::System.Boolean operator !=(MyVo left, System.Int32 right) => !Equals(left.Value, right); + + public static global::System.Boolean operator ==(System.Int32 left, MyVo right) => Equals(left, right.Value); + public static global::System.Boolean operator !=(System.Int32 left, MyVo right) => !Equals(left, right.Value); + + public static explicit operator MyVo(System.Int32 value) => From(value); + public static explicit operator System.Int32(MyVo value) => value.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)); + } + + + /// + /// + /// + /// + /// 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 MyVo result) { + if(System.Int32.TryParse(s, style, provider, out var __v)) { + + + result = new MyVo(__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 MyVo result) { + if(System.Int32.TryParse(s, out var __v)) { + + + result = new MyVo(__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 MyVo result) { + if(System.Int32.TryParse(s, style, provider, out var __v)) { + + + result = new MyVo(__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 MyVo result) { + if(System.Int32.TryParse(s, out var __v)) { + + + result = new MyVo(__v); + return true; + } + + result = default; + return false; + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(global::System.ReadOnlySpan s, global::System.Globalization.NumberStyles style, global::System.IFormatProvider provider) { + var r = System.Int32.Parse(s, style, provider); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s) { + var r = System.Int32.Parse(s); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s, global::System.Globalization.NumberStyles style) { + var r = System.Int32.Parse(s, style); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s, global::System.Globalization.NumberStyles style, global::System.IFormatProvider provider) { + var r = System.Int32.Parse(s, style, provider); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s, global::System.IFormatProvider provider) { + var r = System.Int32.Parse(s, provider); + 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.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); + } + } + + + + + /// Returns the string representation of the underlying . + /// + public override global::System.String ToString() => _isInitialized ? Value.ToString() : "[UNINITIALIZED]"; + + + class MyVoSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override MyVo Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + { +#if NET5_0_OR_GREATER + return MyVo.__Deserialize( + options.NumberHandling == global::System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString && reader.TokenType == global::System.Text.Json.JsonTokenType.String + ? global::System.Int32.Parse(reader.GetString(), global::System.Globalization.NumberStyles.Any, global::System.Globalization.CultureInfo.InvariantCulture) + : reader.GetInt32() + ); +#else + return MyVo.__Deserialize(reader.GetInt32()); +#endif + } + + public override void Write(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options) + { + writer.WriteNumberValue(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(global::System.Int32.Parse(reader.GetString(), global::System.Globalization.NumberStyles.Any, global::System.Globalization.CultureInfo.InvariantCulture)); + } + + public override void WriteAsPropertyName(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options) + { + writer.WritePropertyName(value.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture)); + } +#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.Int32) || sourceType == typeof(global::System.String) || base.CanConvertFrom(context, sourceType); + } + + public override global::System.Object ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Globalization.CultureInfo culture, global::System.Object value) + { + return value switch + { + global::System.Int32 intValue => MyVo.__Deserialize(intValue), + global::System.String stringValue when !global::System.String.IsNullOrEmpty(stringValue) && global::System.Int32.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.Int32) || sourceType == typeof(global::System.String) || base.CanConvertTo(context, sourceType); + } + + public override object ConvertTo(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Globalization.CultureInfo culture, global::System.Object value, global::System.Type destinationType) + { + if (value is MyVo idValue) + { + if (destinationType == typeof(global::System.Int32)) + { + return idValue.Value; + } + + if (destinationType == typeof(global::System.String)) + { + return idValue.Value.ToString(); + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + + + + + internal sealed class MyVoDebugView + { + private readonly MyVo _t; + + MyVoDebugView(MyVo t) + { + _t = t; + } + + public global::System.String UnderlyingType => "System.Int32"; + public System.Int32 Value => _t.Value ; + + public global::System.String Conversions => @"[global::System.Text.Json.Serialization.JsonConverter(typeof(MyVoSystemTextJsonConverter))] +[global::System.ComponentModel.TypeConverter(typeof(MyVoTypeConverter))] +"; + } + } + +} \ No newline at end of file diff --git a/tests/SnapshotTests/InstanceFields/snapshots/snap-v4.6.1/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt b/tests/SnapshotTests/InstanceFields/snapshots/snap-v4.6.1/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt new file mode 100644 index 0000000000..17fc4e0896 --- /dev/null +++ b/tests/SnapshotTests/InstanceFields/snapshots/snap-v4.6.1/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt @@ -0,0 +1,388 @@ +// ------------------------------------------------------------------------------ +// +// 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 + +// Suppress warnings about CS1591: Missing XML comment for publicly visible type or member 'Type_or_Member' +#pragma warning disable CS1591 + +using Vogen; + +namespace Whatever +{ + + [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.Int32, Value = { _value }")] + public partial class MyVo : global::System.IEquatable, global::System.IEquatable , global::System.IComparable, global::System.IComparable + { +#if DEBUG + private readonly global::System.Diagnostics.StackTrace _stackTrace = null; +#endif + private readonly global::System.Boolean _isInitialized; + private readonly System.Int32 _value; + +/// +/// Gets the underlying value if set, otherwise a is thrown. +/// +public System.Int32 Value + { + [global::System.Diagnostics.DebuggerStepThroughAttribute] + get + { + EnsureInitialized(); + return _value; + } + } + + + [global::System.Diagnostics.DebuggerStepThroughAttribute] + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + public MyVo() + { +#if DEBUG + _stackTrace = new global::System.Diagnostics.StackTrace(); +#endif + _isInitialized = false; + _value = default; + } + + [global::System.Diagnostics.DebuggerStepThroughAttribute] + private MyVo(System.Int32 value) + { + _value = value; + _isInitialized = true; + } + + /// + /// Builds an instance from the provided underlying type. + /// + /// The underlying type. + /// An instance of this type. + public static MyVo From(System.Int32 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.Int32 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.Default.Equals(Value, other.Value); + } + public global::System.Boolean Equals(MyVo other, global::System.Collections.Generic.IEqualityComparer comparer) + { + return comparer.Equals(this, other); + } + + + public global::System.Boolean Equals(System.Int32 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.Int32 right) => Equals(left.Value, right); + public static global::System.Boolean operator !=(MyVo left, System.Int32 right) => !Equals(left.Value, right); + + public static global::System.Boolean operator ==(System.Int32 left, MyVo right) => Equals(left, right.Value); + public static global::System.Boolean operator !=(System.Int32 left, MyVo right) => !Equals(left, right.Value); + + public static explicit operator MyVo(System.Int32 value) => From(value); + public static explicit operator System.Int32(MyVo value) => value.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)); + } + + + /// + /// + /// + /// + /// 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 MyVo result) { + if(System.Int32.TryParse(s, style, provider, out var __v)) { + + + result = new MyVo(__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 MyVo result) { + if(System.Int32.TryParse(s, out var __v)) { + + + result = new MyVo(__v); + return true; + } + + result = default; + return false; + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s) { + var r = System.Int32.Parse(s); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s, global::System.Globalization.NumberStyles style) { + var r = System.Int32.Parse(s, style); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s, global::System.Globalization.NumberStyles style, global::System.IFormatProvider provider) { + var r = System.Int32.Parse(s, style, provider); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s, global::System.IFormatProvider provider) { + var r = System.Int32.Parse(s, provider); + 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.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); + } + } + + + + + /// Returns the string representation of the underlying . + /// + public override global::System.String ToString() => _isInitialized ? Value.ToString() : "[UNINITIALIZED]"; + + + class MyVoSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override MyVo Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + { +#if NET5_0_OR_GREATER + return MyVo.__Deserialize( + options.NumberHandling == global::System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString && reader.TokenType == global::System.Text.Json.JsonTokenType.String + ? global::System.Int32.Parse(reader.GetString(), global::System.Globalization.NumberStyles.Any, global::System.Globalization.CultureInfo.InvariantCulture) + : reader.GetInt32() + ); +#else + return MyVo.__Deserialize(reader.GetInt32()); +#endif + } + + public override void Write(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options) + { + writer.WriteNumberValue(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(global::System.Int32.Parse(reader.GetString(), global::System.Globalization.NumberStyles.Any, global::System.Globalization.CultureInfo.InvariantCulture)); + } + + public override void WriteAsPropertyName(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options) + { + writer.WritePropertyName(value.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture)); + } +#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.Int32) || sourceType == typeof(global::System.String) || base.CanConvertFrom(context, sourceType); + } + + public override global::System.Object ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Globalization.CultureInfo culture, global::System.Object value) + { + return value switch + { + global::System.Int32 intValue => MyVo.__Deserialize(intValue), + global::System.String stringValue when !global::System.String.IsNullOrEmpty(stringValue) && global::System.Int32.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.Int32) || sourceType == typeof(global::System.String) || base.CanConvertTo(context, sourceType); + } + + public override object ConvertTo(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Globalization.CultureInfo culture, global::System.Object value, global::System.Type destinationType) + { + if (value is MyVo idValue) + { + if (destinationType == typeof(global::System.Int32)) + { + return idValue.Value; + } + + if (destinationType == typeof(global::System.String)) + { + return idValue.Value.ToString(); + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + + + + + internal sealed class MyVoDebugView + { + private readonly MyVo _t; + + MyVoDebugView(MyVo t) + { + _t = t; + } + + public global::System.String UnderlyingType => "System.Int32"; + public System.Int32 Value => _t.Value ; + + public global::System.String Conversions => @"[global::System.Text.Json.Serialization.JsonConverter(typeof(MyVoSystemTextJsonConverter))] +[global::System.ComponentModel.TypeConverter(typeof(MyVoTypeConverter))] +"; + } + } + +} \ No newline at end of file diff --git a/tests/SnapshotTests/InstanceFields/snapshots/snap-v4.8/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt b/tests/SnapshotTests/InstanceFields/snapshots/snap-v4.8/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt new file mode 100644 index 0000000000..b4f3fefd96 --- /dev/null +++ b/tests/SnapshotTests/InstanceFields/snapshots/snap-v4.8/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt @@ -0,0 +1,388 @@ +// ------------------------------------------------------------------------------ +// +// 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 + +// Suppress warnings about CS1591: Missing XML comment for publicly visible type or member 'Type_or_Member' +#pragma warning disable CS1591 + +using Vogen; + +namespace Whatever +{ + + [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.Int32, Value = { _value }")] + public partial class MyVo : global::System.IEquatable, global::System.IEquatable , global::System.IComparable, global::System.IComparable + { +#if DEBUG + private readonly global::System.Diagnostics.StackTrace _stackTrace = null; +#endif + private readonly global::System.Boolean _isInitialized; + private readonly System.Int32 _value; + +/// +/// Gets the underlying value if set, otherwise a is thrown. +/// +public System.Int32 Value + { + [global::System.Diagnostics.DebuggerStepThroughAttribute] + get + { + EnsureInitialized(); + return _value; + } + } + + + [global::System.Diagnostics.DebuggerStepThroughAttribute] + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + public MyVo() + { +#if DEBUG + _stackTrace = new global::System.Diagnostics.StackTrace(); +#endif + _isInitialized = false; + _value = default; + } + + [global::System.Diagnostics.DebuggerStepThroughAttribute] + private MyVo(System.Int32 value) + { + _value = value; + _isInitialized = true; + } + + /// + /// Builds an instance from the provided underlying type. + /// + /// The underlying type. + /// An instance of this type. + public static MyVo From(System.Int32 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.Int32 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.Default.Equals(Value, other.Value); + } + public global::System.Boolean Equals(MyVo other, global::System.Collections.Generic.IEqualityComparer comparer) + { + return comparer.Equals(this, other); + } + + + public global::System.Boolean Equals(System.Int32 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.Int32 right) => Equals(left.Value, right); + public static global::System.Boolean operator !=(MyVo left, System.Int32 right) => !Equals(left.Value, right); + + public static global::System.Boolean operator ==(System.Int32 left, MyVo right) => Equals(left, right.Value); + public static global::System.Boolean operator !=(System.Int32 left, MyVo right) => !Equals(left, right.Value); + + public static explicit operator MyVo(System.Int32 value) => From(value); + public static explicit operator System.Int32(MyVo value) => value.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)); + } + + + /// + /// + /// + /// + /// 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 MyVo result) { + if(System.Int32.TryParse(s, out var __v)) { + + + result = new MyVo(__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 MyVo result) { + if(System.Int32.TryParse(s, style, provider, out var __v)) { + + + result = new MyVo(__v); + return true; + } + + result = default; + return false; + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s) { + var r = System.Int32.Parse(s); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s, global::System.Globalization.NumberStyles style) { + var r = System.Int32.Parse(s, style); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s, global::System.IFormatProvider provider) { + var r = System.Int32.Parse(s, provider); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s, global::System.Globalization.NumberStyles style, global::System.IFormatProvider provider) { + var r = System.Int32.Parse(s, style, provider); + 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.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); + } + } + + + + + /// Returns the string representation of the underlying . + /// + public override global::System.String ToString() => _isInitialized ? Value.ToString() : "[UNINITIALIZED]"; + + + class MyVoSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override MyVo Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + { +#if NET5_0_OR_GREATER + return MyVo.__Deserialize( + options.NumberHandling == global::System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString && reader.TokenType == global::System.Text.Json.JsonTokenType.String + ? global::System.Int32.Parse(reader.GetString(), global::System.Globalization.NumberStyles.Any, global::System.Globalization.CultureInfo.InvariantCulture) + : reader.GetInt32() + ); +#else + return MyVo.__Deserialize(reader.GetInt32()); +#endif + } + + public override void Write(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options) + { + writer.WriteNumberValue(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(global::System.Int32.Parse(reader.GetString(), global::System.Globalization.NumberStyles.Any, global::System.Globalization.CultureInfo.InvariantCulture)); + } + + public override void WriteAsPropertyName(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options) + { + writer.WritePropertyName(value.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture)); + } +#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.Int32) || sourceType == typeof(global::System.String) || base.CanConvertFrom(context, sourceType); + } + + public override global::System.Object ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Globalization.CultureInfo culture, global::System.Object value) + { + return value switch + { + global::System.Int32 intValue => MyVo.__Deserialize(intValue), + global::System.String stringValue when !global::System.String.IsNullOrEmpty(stringValue) && global::System.Int32.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.Int32) || sourceType == typeof(global::System.String) || base.CanConvertTo(context, sourceType); + } + + public override object ConvertTo(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Globalization.CultureInfo culture, global::System.Object value, global::System.Type destinationType) + { + if (value is MyVo idValue) + { + if (destinationType == typeof(global::System.Int32)) + { + return idValue.Value; + } + + if (destinationType == typeof(global::System.String)) + { + return idValue.Value.ToString(); + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + + + + + internal sealed class MyVoDebugView + { + private readonly MyVo _t; + + MyVoDebugView(MyVo t) + { + _t = t; + } + + public global::System.String UnderlyingType => "System.Int32"; + public System.Int32 Value => _t.Value ; + + public global::System.String Conversions => @"[global::System.Text.Json.Serialization.JsonConverter(typeof(MyVoSystemTextJsonConverter))] +[global::System.ComponentModel.TypeConverter(typeof(MyVoTypeConverter))] +"; + } + } + +} \ No newline at end of file diff --git a/tests/SnapshotTests/InstanceFields/snapshots/snap-v5.0/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt b/tests/SnapshotTests/InstanceFields/snapshots/snap-v5.0/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt new file mode 100644 index 0000000000..87eef397f8 --- /dev/null +++ b/tests/SnapshotTests/InstanceFields/snapshots/snap-v5.0/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt @@ -0,0 +1,444 @@ +// ------------------------------------------------------------------------------ +// +// 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 + +// Suppress warnings about CS1591: Missing XML comment for publicly visible type or member 'Type_or_Member' +#pragma warning disable CS1591 + +using Vogen; + +namespace Whatever +{ + + [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.Int32, Value = { _value }")] + public partial class MyVo : global::System.IEquatable, global::System.IEquatable , global::System.IComparable, global::System.IComparable + { +#if DEBUG + private readonly global::System.Diagnostics.StackTrace _stackTrace = null; +#endif + private readonly global::System.Boolean _isInitialized; + private readonly System.Int32 _value; + +/// +/// Gets the underlying value if set, otherwise a is thrown. +/// +public System.Int32 Value + { + [global::System.Diagnostics.DebuggerStepThroughAttribute] + get + { + EnsureInitialized(); + return _value; + } + } + + + [global::System.Diagnostics.DebuggerStepThroughAttribute] + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + public MyVo() + { +#if DEBUG + _stackTrace = new global::System.Diagnostics.StackTrace(); +#endif + _isInitialized = false; + _value = default; + } + + [global::System.Diagnostics.DebuggerStepThroughAttribute] + private MyVo(System.Int32 value) + { + _value = value; + _isInitialized = true; + } + + /// + /// Builds an instance from the provided underlying type. + /// + /// The underlying type. + /// An instance of this type. + public static MyVo From(System.Int32 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.Int32 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.Default.Equals(Value, other.Value); + } + public global::System.Boolean Equals(MyVo other, global::System.Collections.Generic.IEqualityComparer comparer) + { + return comparer.Equals(this, other); + } + + + public global::System.Boolean Equals(System.Int32 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.Int32 right) => Equals(left.Value, right); + public static global::System.Boolean operator !=(MyVo left, System.Int32 right) => !Equals(left.Value, right); + + public static global::System.Boolean operator ==(System.Int32 left, MyVo right) => Equals(left, right.Value); + public static global::System.Boolean operator !=(System.Int32 left, MyVo right) => !Equals(left, right.Value); + + public static explicit operator MyVo(System.Int32 value) => From(value); + public static explicit operator System.Int32(MyVo value) => value.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)); + } + + + /// + /// + /// + /// + /// 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 MyVo result) { + if(System.Int32.TryParse(s, style, provider, out var __v)) { + + + result = new MyVo(__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 MyVo result) { + if(System.Int32.TryParse(s, out var __v)) { + + + result = new MyVo(__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 MyVo result) { + if(System.Int32.TryParse(s, style, provider, out var __v)) { + + + result = new MyVo(__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 MyVo result) { + if(System.Int32.TryParse(s, out var __v)) { + + + result = new MyVo(__v); + return true; + } + + result = default; + return false; + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(global::System.ReadOnlySpan s, global::System.Globalization.NumberStyles style, global::System.IFormatProvider provider) { + var r = System.Int32.Parse(s, style, provider); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s) { + var r = System.Int32.Parse(s); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s, global::System.Globalization.NumberStyles style) { + var r = System.Int32.Parse(s, style); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s, global::System.Globalization.NumberStyles style, global::System.IFormatProvider provider) { + var r = System.Int32.Parse(s, style, provider); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s, global::System.IFormatProvider provider) { + var r = System.Int32.Parse(s, provider); + 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.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); + } + } + + + + + /// Returns the string representation of the underlying . + /// + public override global::System.String ToString() => _isInitialized ? Value.ToString() : "[UNINITIALIZED]"; + + + class MyVoSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override MyVo Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + { +#if NET5_0_OR_GREATER + return MyVo.__Deserialize( + options.NumberHandling == global::System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString && reader.TokenType == global::System.Text.Json.JsonTokenType.String + ? global::System.Int32.Parse(reader.GetString(), global::System.Globalization.NumberStyles.Any, global::System.Globalization.CultureInfo.InvariantCulture) + : reader.GetInt32() + ); +#else + return MyVo.__Deserialize(reader.GetInt32()); +#endif + } + + public override void Write(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options) + { + writer.WriteNumberValue(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(global::System.Int32.Parse(reader.GetString(), global::System.Globalization.NumberStyles.Any, global::System.Globalization.CultureInfo.InvariantCulture)); + } + + public override void WriteAsPropertyName(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options) + { + writer.WritePropertyName(value.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture)); + } +#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.Int32) || sourceType == typeof(global::System.String) || base.CanConvertFrom(context, sourceType); + } + + public override global::System.Object ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Globalization.CultureInfo culture, global::System.Object value) + { + return value switch + { + global::System.Int32 intValue => MyVo.__Deserialize(intValue), + global::System.String stringValue when !global::System.String.IsNullOrEmpty(stringValue) && global::System.Int32.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.Int32) || sourceType == typeof(global::System.String) || base.CanConvertTo(context, sourceType); + } + + public override object ConvertTo(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Globalization.CultureInfo culture, global::System.Object value, global::System.Type destinationType) + { + if (value is MyVo idValue) + { + if (destinationType == typeof(global::System.Int32)) + { + return idValue.Value; + } + + if (destinationType == typeof(global::System.String)) + { + return idValue.Value.ToString(); + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + + + + + internal sealed class MyVoDebugView + { + private readonly MyVo _t; + + MyVoDebugView(MyVo t) + { + _t = t; + } + + public global::System.String UnderlyingType => "System.Int32"; + public System.Int32 Value => _t.Value ; + + public global::System.String Conversions => @"[global::System.Text.Json.Serialization.JsonConverter(typeof(MyVoSystemTextJsonConverter))] +[global::System.ComponentModel.TypeConverter(typeof(MyVoTypeConverter))] +"; + } + } + +} \ No newline at end of file diff --git a/tests/SnapshotTests/InstanceFields/snapshots/snap-v6.0/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt b/tests/SnapshotTests/InstanceFields/snapshots/snap-v6.0/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt new file mode 100644 index 0000000000..87eef397f8 --- /dev/null +++ b/tests/SnapshotTests/InstanceFields/snapshots/snap-v6.0/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt @@ -0,0 +1,444 @@ +// ------------------------------------------------------------------------------ +// +// 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 + +// Suppress warnings about CS1591: Missing XML comment for publicly visible type or member 'Type_or_Member' +#pragma warning disable CS1591 + +using Vogen; + +namespace Whatever +{ + + [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.Int32, Value = { _value }")] + public partial class MyVo : global::System.IEquatable, global::System.IEquatable , global::System.IComparable, global::System.IComparable + { +#if DEBUG + private readonly global::System.Diagnostics.StackTrace _stackTrace = null; +#endif + private readonly global::System.Boolean _isInitialized; + private readonly System.Int32 _value; + +/// +/// Gets the underlying value if set, otherwise a is thrown. +/// +public System.Int32 Value + { + [global::System.Diagnostics.DebuggerStepThroughAttribute] + get + { + EnsureInitialized(); + return _value; + } + } + + + [global::System.Diagnostics.DebuggerStepThroughAttribute] + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + public MyVo() + { +#if DEBUG + _stackTrace = new global::System.Diagnostics.StackTrace(); +#endif + _isInitialized = false; + _value = default; + } + + [global::System.Diagnostics.DebuggerStepThroughAttribute] + private MyVo(System.Int32 value) + { + _value = value; + _isInitialized = true; + } + + /// + /// Builds an instance from the provided underlying type. + /// + /// The underlying type. + /// An instance of this type. + public static MyVo From(System.Int32 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.Int32 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.Default.Equals(Value, other.Value); + } + public global::System.Boolean Equals(MyVo other, global::System.Collections.Generic.IEqualityComparer comparer) + { + return comparer.Equals(this, other); + } + + + public global::System.Boolean Equals(System.Int32 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.Int32 right) => Equals(left.Value, right); + public static global::System.Boolean operator !=(MyVo left, System.Int32 right) => !Equals(left.Value, right); + + public static global::System.Boolean operator ==(System.Int32 left, MyVo right) => Equals(left, right.Value); + public static global::System.Boolean operator !=(System.Int32 left, MyVo right) => !Equals(left, right.Value); + + public static explicit operator MyVo(System.Int32 value) => From(value); + public static explicit operator System.Int32(MyVo value) => value.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)); + } + + + /// + /// + /// + /// + /// 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 MyVo result) { + if(System.Int32.TryParse(s, style, provider, out var __v)) { + + + result = new MyVo(__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 MyVo result) { + if(System.Int32.TryParse(s, out var __v)) { + + + result = new MyVo(__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 MyVo result) { + if(System.Int32.TryParse(s, style, provider, out var __v)) { + + + result = new MyVo(__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 MyVo result) { + if(System.Int32.TryParse(s, out var __v)) { + + + result = new MyVo(__v); + return true; + } + + result = default; + return false; + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(global::System.ReadOnlySpan s, global::System.Globalization.NumberStyles style, global::System.IFormatProvider provider) { + var r = System.Int32.Parse(s, style, provider); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s) { + var r = System.Int32.Parse(s); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s, global::System.Globalization.NumberStyles style) { + var r = System.Int32.Parse(s, style); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s, global::System.Globalization.NumberStyles style, global::System.IFormatProvider provider) { + var r = System.Int32.Parse(s, style, provider); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s, global::System.IFormatProvider provider) { + var r = System.Int32.Parse(s, provider); + 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.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); + } + } + + + + + /// Returns the string representation of the underlying . + /// + public override global::System.String ToString() => _isInitialized ? Value.ToString() : "[UNINITIALIZED]"; + + + class MyVoSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override MyVo Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + { +#if NET5_0_OR_GREATER + return MyVo.__Deserialize( + options.NumberHandling == global::System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString && reader.TokenType == global::System.Text.Json.JsonTokenType.String + ? global::System.Int32.Parse(reader.GetString(), global::System.Globalization.NumberStyles.Any, global::System.Globalization.CultureInfo.InvariantCulture) + : reader.GetInt32() + ); +#else + return MyVo.__Deserialize(reader.GetInt32()); +#endif + } + + public override void Write(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options) + { + writer.WriteNumberValue(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(global::System.Int32.Parse(reader.GetString(), global::System.Globalization.NumberStyles.Any, global::System.Globalization.CultureInfo.InvariantCulture)); + } + + public override void WriteAsPropertyName(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options) + { + writer.WritePropertyName(value.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture)); + } +#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.Int32) || sourceType == typeof(global::System.String) || base.CanConvertFrom(context, sourceType); + } + + public override global::System.Object ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Globalization.CultureInfo culture, global::System.Object value) + { + return value switch + { + global::System.Int32 intValue => MyVo.__Deserialize(intValue), + global::System.String stringValue when !global::System.String.IsNullOrEmpty(stringValue) && global::System.Int32.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.Int32) || sourceType == typeof(global::System.String) || base.CanConvertTo(context, sourceType); + } + + public override object ConvertTo(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Globalization.CultureInfo culture, global::System.Object value, global::System.Type destinationType) + { + if (value is MyVo idValue) + { + if (destinationType == typeof(global::System.Int32)) + { + return idValue.Value; + } + + if (destinationType == typeof(global::System.String)) + { + return idValue.Value.ToString(); + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + + + + + internal sealed class MyVoDebugView + { + private readonly MyVo _t; + + MyVoDebugView(MyVo t) + { + _t = t; + } + + public global::System.String UnderlyingType => "System.Int32"; + public System.Int32 Value => _t.Value ; + + public global::System.String Conversions => @"[global::System.Text.Json.Serialization.JsonConverter(typeof(MyVoSystemTextJsonConverter))] +[global::System.ComponentModel.TypeConverter(typeof(MyVoTypeConverter))] +"; + } + } + +} \ No newline at end of file diff --git a/tests/SnapshotTests/InstanceFields/snapshots/snap-v7.0/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt b/tests/SnapshotTests/InstanceFields/snapshots/snap-v7.0/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt new file mode 100644 index 0000000000..9e358f1257 --- /dev/null +++ b/tests/SnapshotTests/InstanceFields/snapshots/snap-v7.0/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt @@ -0,0 +1,500 @@ +// ------------------------------------------------------------------------------ +// +// 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 + +// Suppress warnings about CS1591: Missing XML comment for publicly visible type or member 'Type_or_Member' +#pragma warning disable CS1591 + +using Vogen; + +namespace Whatever +{ + + [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.Int32, Value = { _value }")] + public partial class MyVo : global::System.IEquatable, global::System.IEquatable , global::System.IComparable, global::System.IComparable, global::System.IParsable, global::System.ISpanParsable + { +#if DEBUG + private readonly global::System.Diagnostics.StackTrace _stackTrace = null; +#endif + private readonly global::System.Boolean _isInitialized; + private readonly System.Int32 _value; + +/// +/// Gets the underlying value if set, otherwise a is thrown. +/// +public System.Int32 Value + { + [global::System.Diagnostics.DebuggerStepThroughAttribute] + get + { + EnsureInitialized(); + return _value; + } + } + + + [global::System.Diagnostics.DebuggerStepThroughAttribute] + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + public MyVo() + { +#if DEBUG + _stackTrace = new global::System.Diagnostics.StackTrace(); +#endif + _isInitialized = false; + _value = default; + } + + [global::System.Diagnostics.DebuggerStepThroughAttribute] + private MyVo(System.Int32 value) + { + _value = value; + _isInitialized = true; + } + + /// + /// Builds an instance from the provided underlying type. + /// + /// The underlying type. + /// An instance of this type. + public static MyVo From(System.Int32 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.Int32 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.Default.Equals(Value, other.Value); + } + public global::System.Boolean Equals(MyVo other, global::System.Collections.Generic.IEqualityComparer comparer) + { + return comparer.Equals(this, other); + } + + + public global::System.Boolean Equals(System.Int32 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.Int32 right) => Equals(left.Value, right); + public static global::System.Boolean operator !=(MyVo left, System.Int32 right) => !Equals(left.Value, right); + + public static global::System.Boolean operator ==(System.Int32 left, MyVo right) => Equals(left, right.Value); + public static global::System.Boolean operator !=(System.Int32 left, MyVo right) => !Equals(left, right.Value); + + public static explicit operator MyVo(System.Int32 value) => From(value); + public static explicit operator System.Int32(MyVo value) => value.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)); + } + + + /// + /// + /// + /// + /// 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 MyVo result) { + if(System.Int32.TryParse(s, style, provider, out var __v)) { + + + result = new MyVo(__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 MyVo result) { + if(System.Int32.TryParse(s, provider, out var __v)) { + + + result = new MyVo(__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 MyVo result) { + if(System.Int32.TryParse(s, out var __v)) { + + + result = new MyVo(__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 MyVo result) { + if(System.Int32.TryParse(s, style, provider, out var __v)) { + + + result = new MyVo(__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 MyVo result) { + if(System.Int32.TryParse(s, provider, out var __v)) { + + + result = new MyVo(__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 MyVo result) { + if(System.Int32.TryParse(s, out var __v)) { + + + result = new MyVo(__v); + return true; + } + + result = default; + return false; + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(global::System.ReadOnlySpan s, global::System.Globalization.NumberStyles style, global::System.IFormatProvider provider) { + var r = System.Int32.Parse(s, style, provider); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(global::System.ReadOnlySpan s, global::System.IFormatProvider provider) { + var r = System.Int32.Parse(s, provider); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s) { + var r = System.Int32.Parse(s); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s, global::System.Globalization.NumberStyles style) { + var r = System.Int32.Parse(s, style); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s, global::System.Globalization.NumberStyles style, global::System.IFormatProvider provider) { + var r = System.Int32.Parse(s, style, provider); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s, global::System.IFormatProvider provider) { + var r = System.Int32.Parse(s, provider); + 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.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); + } + } + + + + + /// Returns the string representation of the underlying . + /// + public override global::System.String ToString() => _isInitialized ? Value.ToString() : "[UNINITIALIZED]"; + + + class MyVoSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override MyVo Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + { +#if NET5_0_OR_GREATER + return MyVo.__Deserialize( + options.NumberHandling == global::System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString && reader.TokenType == global::System.Text.Json.JsonTokenType.String + ? global::System.Int32.Parse(reader.GetString(), global::System.Globalization.NumberStyles.Any, global::System.Globalization.CultureInfo.InvariantCulture) + : reader.GetInt32() + ); +#else + return MyVo.__Deserialize(reader.GetInt32()); +#endif + } + + public override void Write(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options) + { + writer.WriteNumberValue(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(global::System.Int32.Parse(reader.GetString(), global::System.Globalization.NumberStyles.Any, global::System.Globalization.CultureInfo.InvariantCulture)); + } + + public override void WriteAsPropertyName(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options) + { + writer.WritePropertyName(value.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture)); + } +#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.Int32) || sourceType == typeof(global::System.String) || base.CanConvertFrom(context, sourceType); + } + + public override global::System.Object ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Globalization.CultureInfo culture, global::System.Object value) + { + return value switch + { + global::System.Int32 intValue => MyVo.__Deserialize(intValue), + global::System.String stringValue when !global::System.String.IsNullOrEmpty(stringValue) && global::System.Int32.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.Int32) || sourceType == typeof(global::System.String) || base.CanConvertTo(context, sourceType); + } + + public override object ConvertTo(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Globalization.CultureInfo culture, global::System.Object value, global::System.Type destinationType) + { + if (value is MyVo idValue) + { + if (destinationType == typeof(global::System.Int32)) + { + return idValue.Value; + } + + if (destinationType == typeof(global::System.String)) + { + return idValue.Value.ToString(); + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + + + + + internal sealed class MyVoDebugView + { + private readonly MyVo _t; + + MyVoDebugView(MyVo t) + { + _t = t; + } + + public global::System.String UnderlyingType => "System.Int32"; + public System.Int32 Value => _t.Value ; + + public global::System.String Conversions => @"[global::System.Text.Json.Serialization.JsonConverter(typeof(MyVoSystemTextJsonConverter))] +[global::System.ComponentModel.TypeConverter(typeof(MyVoTypeConverter))] +"; + } + } + +} \ No newline at end of file diff --git a/tests/SnapshotTests/InstanceFields/snapshots/snap-v8.0/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt b/tests/SnapshotTests/InstanceFields/snapshots/snap-v8.0/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt new file mode 100644 index 0000000000..ff6b70df70 --- /dev/null +++ b/tests/SnapshotTests/InstanceFields/snapshots/snap-v8.0/InstanceFieldGenerationTests.Instances_can_be_newed_up_in_the_wrapper_itself.verified.txt @@ -0,0 +1,590 @@ +// ------------------------------------------------------------------------------ +// +// 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 + +// Suppress warnings about CS1591: Missing XML comment for publicly visible type or member 'Type_or_Member' +#pragma warning disable CS1591 + +using Vogen; + +namespace Whatever +{ + + [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.Int32, Value = { _value }")] + public partial class MyVo : global::System.IEquatable, global::System.IEquatable , global::System.IComparable, global::System.IComparable, global::System.IParsable, global::System.ISpanParsable, global::System.IUtf8SpanParsable + { +#if DEBUG + private readonly global::System.Diagnostics.StackTrace _stackTrace = null; +#endif + private readonly global::System.Boolean _isInitialized; + private readonly System.Int32 _value; + +/// +/// Gets the underlying value if set, otherwise a is thrown. +/// +public System.Int32 Value + { + [global::System.Diagnostics.DebuggerStepThroughAttribute] + get + { + EnsureInitialized(); + return _value; + } + } + + + [global::System.Diagnostics.DebuggerStepThroughAttribute] + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + public MyVo() + { +#if DEBUG + _stackTrace = new global::System.Diagnostics.StackTrace(); +#endif + _isInitialized = false; + _value = default; + } + + [global::System.Diagnostics.DebuggerStepThroughAttribute] + private MyVo(System.Int32 value) + { + _value = value; + _isInitialized = true; + } + + /// + /// Builds an instance from the provided underlying type. + /// + /// The underlying type. + /// An instance of this type. + public static MyVo From(System.Int32 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.Int32 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.Default.Equals(Value, other.Value); + } + public global::System.Boolean Equals(MyVo other, global::System.Collections.Generic.IEqualityComparer comparer) + { + return comparer.Equals(this, other); + } + + + public global::System.Boolean Equals(System.Int32 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.Int32 right) => Equals(left.Value, right); + public static global::System.Boolean operator !=(MyVo left, System.Int32 right) => !Equals(left.Value, right); + + public static global::System.Boolean operator ==(System.Int32 left, MyVo right) => Equals(left, right.Value); + public static global::System.Boolean operator !=(System.Int32 left, MyVo right) => !Equals(left, right.Value); + + public static explicit operator MyVo(System.Int32 value) => From(value); + public static explicit operator System.Int32(MyVo value) => value.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)); + } + + + /// + /// + /// + /// + /// 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 MyVo result) { + if(System.Int32.TryParse(utf8Text, style, provider, out var __v)) { + + + result = new MyVo(__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 MyVo result) { + if(System.Int32.TryParse(utf8Text, provider, out var __v)) { + + + result = new MyVo(__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 MyVo result) { + if(System.Int32.TryParse(utf8Text, out var __v)) { + + + result = new MyVo(__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 MyVo result) { + if(System.Int32.TryParse(s, style, provider, out var __v)) { + + + result = new MyVo(__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 MyVo result) { + if(System.Int32.TryParse(s, provider, out var __v)) { + + + result = new MyVo(__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 MyVo result) { + if(System.Int32.TryParse(s, out var __v)) { + + + result = new MyVo(__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 MyVo result) { + if(System.Int32.TryParse(s, style, provider, out var __v)) { + + + result = new MyVo(__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 MyVo result) { + if(System.Int32.TryParse(s, provider, out var __v)) { + + + result = new MyVo(__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 MyVo result) { + if(System.Int32.TryParse(s, out var __v)) { + + + result = new MyVo(__v); + return true; + } + + result = default; + return false; + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(global::System.ReadOnlySpan utf8Text, global::System.Globalization.NumberStyles style, global::System.IFormatProvider provider) { + var r = System.Int32.Parse(utf8Text, style, provider); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(global::System.ReadOnlySpan utf8Text, global::System.IFormatProvider provider) { + var r = System.Int32.Parse(utf8Text, provider); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(global::System.ReadOnlySpan s, global::System.Globalization.NumberStyles style, global::System.IFormatProvider provider) { + var r = System.Int32.Parse(s, style, provider); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(global::System.ReadOnlySpan s, global::System.IFormatProvider provider) { + var r = System.Int32.Parse(s, provider); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s) { + var r = System.Int32.Parse(s); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s, global::System.Globalization.NumberStyles style) { + var r = System.Int32.Parse(s, style); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s, global::System.Globalization.NumberStyles style, global::System.IFormatProvider provider) { + var r = System.Int32.Parse(s, style, provider); + return From(r); + } + + /// + /// + /// + /// + /// The value created via the method. + /// + /// Thrown when the value can be parsed, but is not valid. + public static MyVo Parse(string s, global::System.IFormatProvider provider) { + var r = System.Int32.Parse(s, provider); + 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.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); + } + } + + + + + /// Returns the string representation of the underlying . + /// + public override global::System.String ToString() => _isInitialized ? Value.ToString() : "[UNINITIALIZED]"; + + + class MyVoSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override MyVo Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + { +#if NET5_0_OR_GREATER + return MyVo.__Deserialize( + options.NumberHandling == global::System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString && reader.TokenType == global::System.Text.Json.JsonTokenType.String + ? global::System.Int32.Parse(reader.GetString(), global::System.Globalization.NumberStyles.Any, global::System.Globalization.CultureInfo.InvariantCulture) + : reader.GetInt32() + ); +#else + return MyVo.__Deserialize(reader.GetInt32()); +#endif + } + + public override void Write(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options) + { + writer.WriteNumberValue(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(global::System.Int32.Parse(reader.GetString(), global::System.Globalization.NumberStyles.Any, global::System.Globalization.CultureInfo.InvariantCulture)); + } + + public override void WriteAsPropertyName(System.Text.Json.Utf8JsonWriter writer, MyVo value, global::System.Text.Json.JsonSerializerOptions options) + { + writer.WritePropertyName(value.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture)); + } +#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.Int32) || sourceType == typeof(global::System.String) || base.CanConvertFrom(context, sourceType); + } + + public override global::System.Object ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Globalization.CultureInfo culture, global::System.Object value) + { + return value switch + { + global::System.Int32 intValue => MyVo.__Deserialize(intValue), + global::System.String stringValue when !global::System.String.IsNullOrEmpty(stringValue) && global::System.Int32.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.Int32) || sourceType == typeof(global::System.String) || base.CanConvertTo(context, sourceType); + } + + public override object ConvertTo(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Globalization.CultureInfo culture, global::System.Object value, global::System.Type destinationType) + { + if (value is MyVo idValue) + { + if (destinationType == typeof(global::System.Int32)) + { + return idValue.Value; + } + + if (destinationType == typeof(global::System.String)) + { + return idValue.Value.ToString(); + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + + + + + internal sealed class MyVoDebugView + { + private readonly MyVo _t; + + MyVoDebugView(MyVo t) + { + _t = t; + } + + public global::System.String UnderlyingType => "System.Int32"; + public System.Int32 Value => _t.Value ; + + public global::System.String Conversions => @"[global::System.Text.Json.Serialization.JsonConverter(typeof(MyVoSystemTextJsonConverter))] +[global::System.ComponentModel.TypeConverter(typeof(MyVoTypeConverter))] +"; + } + } + +} \ No newline at end of file diff --git a/tests/SnapshotTests/SnapshotRunner.cs b/tests/SnapshotTests/SnapshotRunner.cs index 170ca25742..ddb90aa912 100644 --- a/tests/SnapshotTests/SnapshotRunner.cs +++ b/tests/SnapshotTests/SnapshotRunner.cs @@ -121,7 +121,7 @@ public async Task RunOn(params TargetFramework[] frameworks) } } - private (ImmutableArray Diagnostics, string Output) GetGeneratedOutput(string source, TargetFramework targetFramework) + private (ImmutableArray Diagnostics, string GeneratedSource) GetGeneratedOutput(string source, TargetFramework targetFramework) { var r = MetadataReference.CreateFromFile(typeof(ValueObjectAttribute).Assembly.Location);