diff --git a/.github/workflows/BuildAndPack.yml b/.github/workflows/BuildAndPack.yml
index cdd141ece..60e5a5e3e 100644
--- a/.github/workflows/BuildAndPack.yml
+++ b/.github/workflows/BuildAndPack.yml
@@ -36,6 +36,7 @@ jobs:
- uses: actions/setup-dotnet@v3
with:
dotnet-version: |
+ 8.0.x
7.0.x
6.0.x
5.0.x
@@ -66,6 +67,7 @@ jobs:
- uses: actions/setup-dotnet@v3
with:
dotnet-version: |
+ 8.0.x
7.0.x
6.0.x
5.0.x
@@ -96,6 +98,7 @@ jobs:
- uses: actions/setup-dotnet@v3
with:
dotnet-version: |
+ 8.0.x
7.0.x
6.0.x
5.0.x
diff --git a/.gitignore b/.gitignore
index d662c941d..71494e00d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -245,3 +245,6 @@ ModelManifest.xml
.fake/
tools/*
!tools/packages.config
+
+# NuGet testing
+globalPackagesFolder
\ No newline at end of file
diff --git a/NuGet.integration-tests.config b/NuGet.integration-tests.config
index 59eaf0656..c71f27319 100644
--- a/NuGet.integration-tests.config
+++ b/NuGet.integration-tests.config
@@ -1,8 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/StronglyTypedId.sln b/StronglyTypedId.sln
index cd44309c6..4620315b7 100644
--- a/StronglyTypedId.sln
+++ b/StronglyTypedId.sln
@@ -32,6 +32,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StronglyTypedIds.Nuget.Inte
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StronglyTypedIds.Nuget.Attributes.IntegrationTests", "test\StronglyTypedIds.Nuget.Attributes.IntegrationTests\StronglyTypedIds.Nuget.Attributes.IntegrationTests.csproj", "{19A9B323-8C0B-4D1B-A20C-8CECFFD37F23}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StronglyTypedIds.Templates", "src\StronglyTypedIds.Templates\StronglyTypedIds.Templates.csproj", "{336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StronglyTypedIds.IntegrationTests.Types", "test\StronglyTypedIds.IntegrationTests.Types\StronglyTypedIds.IntegrationTests.Types.csproj", "{A5804404-E5A5-4F05-86E2-B2A11D370498}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StronglyTypedIds.IntegrationTests.ExternalIds", "test\StronglyTypedIds.IntegrationTests.ExternalIds\StronglyTypedIds.IntegrationTests.ExternalIds.csproj", "{07875BB0-EFEE-4F90-AAB8-4B11F78C8047}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -104,6 +110,42 @@ Global
{19A9B323-8C0B-4D1B-A20C-8CECFFD37F23}.Release|Any CPU.ActiveCfg = Release|Any CPU
{19A9B323-8C0B-4D1B-A20C-8CECFFD37F23}.Release|x64.ActiveCfg = Release|Any CPU
{19A9B323-8C0B-4D1B-A20C-8CECFFD37F23}.Release|x86.ActiveCfg = Release|Any CPU
+ {336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Debug|x64.Build.0 = Debug|Any CPU
+ {336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Debug|x86.Build.0 = Debug|Any CPU
+ {336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Release|x64.ActiveCfg = Release|Any CPU
+ {336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Release|x64.Build.0 = Release|Any CPU
+ {336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Release|x86.ActiveCfg = Release|Any CPU
+ {336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Release|x86.Build.0 = Release|Any CPU
+ {A5804404-E5A5-4F05-86E2-B2A11D370498}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A5804404-E5A5-4F05-86E2-B2A11D370498}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A5804404-E5A5-4F05-86E2-B2A11D370498}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {A5804404-E5A5-4F05-86E2-B2A11D370498}.Debug|x64.Build.0 = Debug|Any CPU
+ {A5804404-E5A5-4F05-86E2-B2A11D370498}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {A5804404-E5A5-4F05-86E2-B2A11D370498}.Debug|x86.Build.0 = Debug|Any CPU
+ {A5804404-E5A5-4F05-86E2-B2A11D370498}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A5804404-E5A5-4F05-86E2-B2A11D370498}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A5804404-E5A5-4F05-86E2-B2A11D370498}.Release|x64.ActiveCfg = Release|Any CPU
+ {A5804404-E5A5-4F05-86E2-B2A11D370498}.Release|x64.Build.0 = Release|Any CPU
+ {A5804404-E5A5-4F05-86E2-B2A11D370498}.Release|x86.ActiveCfg = Release|Any CPU
+ {A5804404-E5A5-4F05-86E2-B2A11D370498}.Release|x86.Build.0 = Release|Any CPU
+ {07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Debug|x64.Build.0 = Debug|Any CPU
+ {07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Debug|x86.Build.0 = Debug|Any CPU
+ {07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Release|Any CPU.Build.0 = Release|Any CPU
+ {07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Release|x64.ActiveCfg = Release|Any CPU
+ {07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Release|x64.Build.0 = Release|Any CPU
+ {07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Release|x86.ActiveCfg = Release|Any CPU
+ {07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -115,6 +157,9 @@ Global
{F25F6E67-E62A-4075-86CF-4C4EDD7E4883} = {EE1258BD-3422-4F55-B9CF-B4D6C95DAD68}
{A7355210-7DDC-4968-84B7-79002113EA6E} = {D1907D86-8FFC-4178-A3DB-0ADBDD282C64}
{19A9B323-8C0B-4D1B-A20C-8CECFFD37F23} = {D1907D86-8FFC-4178-A3DB-0ADBDD282C64}
+ {336D7EE4-90BA-4BFC-99F6-D70B8D494E8C} = {EE1258BD-3422-4F55-B9CF-B4D6C95DAD68}
+ {A5804404-E5A5-4F05-86E2-B2A11D370498} = {D1907D86-8FFC-4178-A3DB-0ADBDD282C64}
+ {07875BB0-EFEE-4F90-AAB8-4B11F78C8047} = {D1907D86-8FFC-4178-A3DB-0ADBDD282C64}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8D1F0534-B8AD-4CFA-9C14-CBC757BCB1E1}
diff --git a/src/StronglyTypedIds.Attributes/StronglyTypedIdAttribute.cs b/src/StronglyTypedIds.Attributes/StronglyTypedIdAttribute.cs
index 68ec67dc9..6f6ea829d 100644
--- a/src/StronglyTypedIds.Attributes/StronglyTypedIdAttribute.cs
+++ b/src/StronglyTypedIds.Attributes/StronglyTypedIdAttribute.cs
@@ -1,48 +1,49 @@
-using System;
+//------------------------------------------------------------------------------
+//
+// This code was generated by the StronglyTypedId source generator
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+#pragma warning disable 1591 // publicly visible type or member must be documented
+
+#nullable enable
namespace StronglyTypedIds
{
///
/// Place on partial structs to make the type a strongly-typed ID
///
- [AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)]
- [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")]
- public sealed class StronglyTypedIdAttribute : Attribute
+ [global::System.AttributeUsage(global::System.AttributeTargets.Struct, Inherited = false, AllowMultiple = false)]
+ [global::System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")]
+ public sealed class StronglyTypedIdAttribute : global::System.Attribute
{
///
- /// Make the struct a strongly typed ID
+ /// Make the struct a strongly typed ID.
///
- /// The to use to store the strongly-typed ID value.
- /// If not set, uses , which defaults to
- /// Converters to create for serializing/deserializing the strongly-typed ID value.
- /// If not set, uses , which defaults to
- /// and
- /// Interfaces and patterns the strongly typed id should implement
- /// If not set, uses , which defaults to
- /// and
- public StronglyTypedIdAttribute(
- StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default,
- StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default,
- StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default)
+ /// The built-in template to use to generate the ID.
+ /// The names of additional custom templates to use to generate the ID.
+ /// Templates must be added to the project using the format NAME.typedid,
+ /// where NAME is the name of the template passed in .
+ ///
+ public StronglyTypedIdAttribute(global::StronglyTypedIds.Template template, params string[] templateNames)
{
- BackingType = backingType;
- Converters = converters;
- Implementations = implementations;
}
///
- /// The to use to store the strongly-typed ID value
- ///
- public StronglyTypedIdBackingType BackingType { get; }
-
- ///
- /// JSON library used to serialize/deserialize strongly-typed ID value
+ /// Make the struct a strongly typed ID.
///
- public StronglyTypedIdConverter Converters { get; }
-
- ///
- /// Interfaces and patterns the strongly typed id should implement
- ///
- public StronglyTypedIdImplementations Implementations { get; }
+ /// The names of the template to use to generate the ID.
+ /// Templates must be added to the project using the format NAME.typedid,
+ /// where NAME is the name of the template passed in .
+ /// If no templates are provided, the default value is used, as specified by
+ /// , or alternatively the
+ /// template.
+ ///
+ public StronglyTypedIdAttribute(params string[] templateNames)
+ {
+ }
}
}
\ No newline at end of file
diff --git a/src/StronglyTypedIds.Attributes/StronglyTypedIdBackingType.cs b/src/StronglyTypedIds.Attributes/StronglyTypedIdBackingType.cs
deleted file mode 100644
index 0016511b6..000000000
--- a/src/StronglyTypedIds.Attributes/StronglyTypedIdBackingType.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System;
-
-namespace StronglyTypedIds
-{
- ///
- /// The to use to store the value of a strongly-typed ID
- ///
- public enum StronglyTypedIdBackingType
- {
- ///
- /// Use the default backing type (either the globally configured default, or Guid)
- ///
- Default = 0,
-
- Guid = 1,
- Int = 2,
- String = 3,
- Long = 4,
- NullableString = 5,
- MassTransitNewId = 6,
- }
-}
\ No newline at end of file
diff --git a/src/StronglyTypedIds.Attributes/StronglyTypedIdConverter.cs b/src/StronglyTypedIds.Attributes/StronglyTypedIdConverter.cs
deleted file mode 100644
index 599a51409..000000000
--- a/src/StronglyTypedIds.Attributes/StronglyTypedIdConverter.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-using System;
-
-namespace StronglyTypedIds
-{
- ///
- /// Converters used to to serialize/deserialize strongly-typed ID values
- ///
- [Flags]
- public enum StronglyTypedIdConverter
- {
- // Used with HasFlag, so needs to be 1, 2, 4 etc
-
- ///
- /// Don't create any converters for the strongly typed ID
- ///
- None = 0,
-
- ///
- /// Use the default converters for the strongly typed Id.
- /// This will be the value provided in the , which falls back to
- /// and
- ///
- Default = 1,
-
- ///
- /// Creates a for converting from the strongly typed ID to and from a string
- ///
- TypeConverter = 2,
-
- ///
- /// Creates a Newtonsoft.Json.JsonConverter for serializing the strongly typed id to its primitive value
- ///
- NewtonsoftJson = 4,
-
- ///
- /// Creates a System.Text.Json.Serialization.JsonConverter for serializing the strongly typed id to its primitive value
- ///
- SystemTextJson = 8,
-
- ///
- /// Creates an EF Core Value Converter for extracting the primitive value
- ///
- EfCoreValueConverter = 16,
-
- ///
- /// Creates a Dapper TypeHandler for converting to and from the type
- ///
- DapperTypeHandler = 32,
- }
-}
\ No newline at end of file
diff --git a/src/StronglyTypedIds.Attributes/StronglyTypedIdDefaultsAttribute.cs b/src/StronglyTypedIds.Attributes/StronglyTypedIdDefaultsAttribute.cs
index f7cde494b..c4518e1ef 100644
--- a/src/StronglyTypedIds.Attributes/StronglyTypedIdDefaultsAttribute.cs
+++ b/src/StronglyTypedIds.Attributes/StronglyTypedIdDefaultsAttribute.cs
@@ -1,46 +1,58 @@
-using System;
+//------------------------------------------------------------------------------
+//
+// This code was generated by the StronglyTypedId source generator
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+#pragma warning disable 1591 // publicly visible type or member must be documented
+
+#nullable enable
namespace StronglyTypedIds
{
///
- /// Used to control the default Place on partial structs to make the type a strongly-typed ID
+ /// Used to control the default strongly typed ID values. Apply to an assembly using
+ /// [assembly:StronglyTypedIdDefaults(Template.Int)]
for example
///
- [AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)]
- [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")]
- public sealed class StronglyTypedIdDefaultsAttribute : Attribute
+ [global::System.AttributeUsage(global::System.AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)]
+ [global::System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")]
+ public sealed class StronglyTypedIdDefaultsAttribute : global::System.Attribute
{
///
- /// Set the default values used for strongly typed ids
+ /// Set the default template to use for strongly typed IDs
///
- /// The to use to store the strongly-typed ID value.
- /// Defaults to
- /// JSON library used to serialize/deserialize strongly-typed ID value.
- /// Defaults to and
- /// Interfaces and patterns the strongly typed id should implement
- /// Defaults to and
- public StronglyTypedIdDefaultsAttribute(
- StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default,
- StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default,
- StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default)
+ /// The built-in template to use to generate the ID.
+ /// The names of additional custom templates to use to generate the ID.
+ /// Templates must be added to the project using the format NAME.typedid,
+ /// where NAME is the name of the template passed in .
+ ///
+ public StronglyTypedIdDefaultsAttribute(global::StronglyTypedIds.Template template, params string[] templateNames)
{
- BackingType = backingType;
- Converters = converters;
- Implementations = implementations;
}
///
- /// The default to use to store the strongly-typed ID values.
- ///
- public StronglyTypedIdBackingType BackingType { get; }
-
- ///
- /// The default converters to create for serializing/deserializing strongly-typed ID values.
+ /// Set the default template to use for strongly typed IDs
///
- public StronglyTypedIdConverter Converters { get; }
+ /// The name of the template to use to generate the ID.
+ /// Templates must be added to the project using the format NAME.typedid,
+ /// where NAME is the name of the template passed in .
+ ///
+ public StronglyTypedIdDefaultsAttribute(string templateName)
+ {
+ }
///
- /// Interfaces and patterns the strongly typed id should implement
+ /// Set the default template to use for strongly typed IDs
///
- public StronglyTypedIdImplementations Implementations { get; }
+ /// The name of the template to use to generate the ID.
+ /// Templates must be added to the project using the format NAME.typedid,
+ /// where NAME is the name of the template passed in .
+ ///
+ public StronglyTypedIdDefaultsAttribute(string templateName, params string[] templateNames)
+ {
+ }
}
}
\ No newline at end of file
diff --git a/src/StronglyTypedIds.Attributes/StronglyTypedIdImplementations.cs b/src/StronglyTypedIds.Attributes/StronglyTypedIdImplementations.cs
deleted file mode 100644
index d0900fc4f..000000000
--- a/src/StronglyTypedIds.Attributes/StronglyTypedIdImplementations.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using System;
-
-namespace StronglyTypedIds
-{
- ///
- /// Interfaces and patterns the strongly typed id should implement
- ///
- [Flags]
- public enum StronglyTypedIdImplementations
- {
- // Used with HasFlag, so needs to be 1, 2, 4 etc
-
- ///
- /// Don't implement any additional members for the strongly typed ID
- ///
- None = 0,
-
- ///
- /// Use the default implementations for the strongly typed Id.
- /// This will be the value provided in the , which falls back to
- /// and
- ///
- Default = 1,
-
- // ReSharper disable once InconsistentNaming
- ///
- /// Implement the interface
- ///
- IEquatable = 2,
-
- // ReSharper disable once InconsistentNaming
- ///
- /// Implement the interface
- ///
- IComparable = 4,
- }
-}
\ No newline at end of file
diff --git a/src/StronglyTypedIds.Attributes/Template.cs b/src/StronglyTypedIds.Attributes/Template.cs
new file mode 100644
index 000000000..3ac8cfa8a
--- /dev/null
+++ b/src/StronglyTypedIds.Attributes/Template.cs
@@ -0,0 +1,28 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by the StronglyTypedId source generator
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+#pragma warning disable 1591 // publicly visible type or member must be documented
+
+#nullable enable
+
+using System;
+
+namespace StronglyTypedIds
+{
+ ///
+ /// The built-in template to use to generate the strongly-typed ID
+ ///
+ public enum Template
+ {
+ Guid,
+ Int,
+ String,
+ Long,
+ }
+}
\ No newline at end of file
diff --git a/src/StronglyTypedIds.Templates/StronglyTypedId.Templates.targets b/src/StronglyTypedIds.Templates/StronglyTypedId.Templates.targets
new file mode 100644
index 000000000..b7db8fde5
--- /dev/null
+++ b/src/StronglyTypedIds.Templates/StronglyTypedId.Templates.targets
@@ -0,0 +1,8 @@
+
+
+
+
+ true
+
+
+
diff --git a/src/StronglyTypedIds.Templates/StronglyTypedIds.Templates.csproj b/src/StronglyTypedIds.Templates/StronglyTypedIds.Templates.csproj
new file mode 100644
index 000000000..a720ced3a
--- /dev/null
+++ b/src/StronglyTypedIds.Templates/StronglyTypedIds.Templates.csproj
@@ -0,0 +1,17 @@
+
+
+
+ netstandard2.0
+ false
+ enable
+ StronglyTypedId.Templates
+ A collection of templates for generating strongly-typed IDs by decorating with a [StronglyTypedId] attribute
+ latest
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/StronglyTypedIds.Templates/guid-dapper.typedid b/src/StronglyTypedIds.Templates/guid-dapper.typedid
new file mode 100644
index 000000000..2453e2c83
--- /dev/null
+++ b/src/StronglyTypedIds.Templates/guid-dapper.typedid
@@ -0,0 +1,20 @@
+ partial struct PLACEHOLDERID
+ {
+ public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler
+ {
+ public override void SetValue(global::System.Data.IDbDataParameter parameter, PLACEHOLDERID value)
+ {
+ parameter.Value = value.Value;
+ }
+
+ public override PLACEHOLDERID Parse(object value)
+ {
+ return value switch
+ {
+ global::System.Guid guidValue => new PLACEHOLDERID(guidValue),
+ string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new PLACEHOLDERID(result),
+ _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to PLACEHOLDERID"),
+ };
+ }
+ }
+ }
\ No newline at end of file
diff --git a/src/StronglyTypedIds.Templates/guid-efcore.typedid b/src/StronglyTypedIds.Templates/guid-efcore.typedid
new file mode 100644
index 000000000..f6a59d0a5
--- /dev/null
+++ b/src/StronglyTypedIds.Templates/guid-efcore.typedid
@@ -0,0 +1,13 @@
+ partial struct PLACEHOLDERID
+ {
+ public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter
+ {
+ public EfCoreValueConverter() : this(null) { }
+ public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null)
+ : base(
+ id => id.Value,
+ value => new PLACEHOLDERID(value),
+ mappingHints
+ ) { }
+ }
+ }
\ No newline at end of file
diff --git a/src/StronglyTypedIds.Templates/guid-full.typedid b/src/StronglyTypedIds.Templates/guid-full.typedid
new file mode 100644
index 000000000..00a1d2f47
--- /dev/null
+++ b/src/StronglyTypedIds.Templates/guid-full.typedid
@@ -0,0 +1,254 @@
+ [global::System.ComponentModel.TypeConverter(typeof(PLACEHOLDERIDTypeConverter))]
+ [global::System.Text.Json.Serialization.JsonConverter(typeof(PLACEHOLDERIDSystemTextJsonConverter))]
+ [global::Newtonsoft.Json.JsonConverter(typeof(PLACEHOLDERIDNewtonsoftJsonConverter))]
+ partial struct PLACEHOLDERID :
+#if NET6_0_OR_GREATER
+ global::System.ISpanFormattable,
+#endif
+#if NET7_0_OR_GREATER
+ global::System.IParsable, global::System.ISpanParsable,
+#endif
+ global::System.IComparable, global::System.IEquatable, global::System.IFormattable
+ {
+ public global::System.Guid Value { get; }
+
+ public PLACEHOLDERID(global::System.Guid value)
+ {
+ Value = value;
+ }
+
+ public static PLACEHOLDERID New() => new PLACEHOLDERID(global::System.Guid.NewGuid());
+ public static readonly PLACEHOLDERID Empty = new PLACEHOLDERID(global::System.Guid.Empty);
+
+ ///
+ public bool Equals(PLACEHOLDERID other) => this.Value.Equals(other.Value);
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ return obj is PLACEHOLDERID other && Equals(other);
+ }
+
+ public override int GetHashCode() => Value.GetHashCode();
+
+ public override string ToString() => Value.ToString();
+
+ public static bool operator ==(PLACEHOLDERID a, PLACEHOLDERID b) => a.Equals(b);
+ public static bool operator !=(PLACEHOLDERID a, PLACEHOLDERID b) => !(a == b);
+ public static bool operator > (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) > 0;
+ public static bool operator < (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) < 0;
+ public static bool operator >= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) >= 0;
+ public static bool operator <= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) <= 0;
+
+ ///
+ public int CompareTo(PLACEHOLDERID other) => Value.CompareTo(other.Value);
+
+ public partial class PLACEHOLDERIDTypeConverter : global::System.ComponentModel.TypeConverter
+ {
+ public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType)
+ {
+ return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
+ }
+
+ public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value)
+ {
+ return value switch
+ {
+ global::System.Guid guidValue => new PLACEHOLDERID(guidValue),
+ string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new PLACEHOLDERID(result),
+ _ => base.ConvertFrom(context, culture, value),
+ };
+ }
+
+ public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType)
+ {
+ return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType);
+ }
+
+ public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType)
+ {
+ if (value is PLACEHOLDERID idValue)
+ {
+ if (destinationType == typeof(global::System.Guid))
+ {
+ return idValue.Value;
+ }
+
+ if (destinationType == typeof(string))
+ {
+ return idValue.Value.ToString();
+ }
+ }
+
+ return base.ConvertTo(context, culture, value, destinationType);
+ }
+ }
+
+ public partial class PLACEHOLDERIDSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter
+ {
+ public override bool CanConvert(global::System.Type typeToConvert)
+ => typeToConvert == typeof(global::System.Guid) || typeToConvert == typeof(string) || base.CanConvert(typeToConvert);
+
+ public override PLACEHOLDERID Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
+ => new (reader.GetGuid());
+
+ public override void Write(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options)
+ => writer.WriteStringValue(value.Value);
+
+#if NET6_0_OR_GREATER
+ public override PLACEHOLDERID ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
+ => new(global::System.Guid.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the PLACEHOLDERID property was null")));
+
+ public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options)
+ => writer.WritePropertyName(value.Value.ToString());
+#endif
+ }
+
+ public static PLACEHOLDERID Parse(string input)
+ => new(global::System.Guid.Parse(input));
+
+#if NET7_0_OR_GREATER
+ ///
+ public static PLACEHOLDERID Parse(string input, global::System.IFormatProvider? provider)
+ => new(global::System.Guid.Parse(input, provider));
+
+ ///
+ public static bool TryParse(
+ [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input,
+ global::System.IFormatProvider? provider,
+ out PLACEHOLDERID result)
+ {
+ if (input is null)
+ {
+ result = default;
+ return false;
+ }
+
+ if (global::System.Guid.TryParse(input, provider, out var guid))
+ {
+ result = new(guid);
+ return true;
+ }
+ else
+ {
+ result = default;
+ return false;
+ }
+ }
+#endif
+
+ ///
+ public string ToString(
+#if NET7_0_OR_GREATER
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)]
+#endif
+ string? format,
+ global::System.IFormatProvider? formatProvider)
+ => Value.ToString(format, formatProvider);
+
+#if NETCOREAPP2_1_OR_GREATER
+ public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input)
+ => new(global::System.Guid.Parse(input));
+#endif
+
+#if NET6_0_OR_GREATER
+#if NET7_0_OR_GREATER
+ ///
+#endif
+ public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider)
+#if NET7_0_OR_GREATER
+ => new(global::System.Guid.Parse(input, provider));
+#else
+ => new(global::System.Guid.Parse(input));
+#endif
+
+#if NET7_0_OR_GREATER
+ ///
+#endif
+ public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out PLACEHOLDERID result)
+ {
+#if NET7_0_OR_GREATER
+ if (global::System.Guid.TryParse(input, provider, out var guid))
+#else
+ if (global::System.Guid.TryParse(input, out var guid))
+#endif
+ {
+ result = new(guid);
+ return true;
+ }
+ else
+ {
+ result = default;
+ return false;
+ }
+ }
+
+ ///
+ public bool TryFormat(
+ global::System.Span destination,
+ out int charsWritten,
+#if NET7_0_OR_GREATER
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)]
+#endif
+ global::System.ReadOnlySpan format,
+ global::System.IFormatProvider? provider)
+ => Value.TryFormat(destination, out charsWritten, format);
+
+ ///
+ public bool TryFormat(
+ global::System.Span destination,
+ out int charsWritten,
+#if NET7_0_OR_GREATER
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)]
+#endif
+ global::System.ReadOnlySpan format = default)
+ => Value.TryFormat(destination, out charsWritten, format);
+#endif
+
+ public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler
+ {
+ public override void SetValue(global::System.Data.IDbDataParameter parameter, PLACEHOLDERID value)
+ {
+ parameter.Value = value.Value;
+ }
+
+ public override PLACEHOLDERID Parse(object value)
+ {
+ return value switch
+ {
+ global::System.Guid guidValue => new PLACEHOLDERID(guidValue),
+ string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new PLACEHOLDERID(result),
+ _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to PLACEHOLDERID"),
+ };
+ }
+ }
+
+ public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter
+ {
+ public EfCoreValueConverter() : this(null) { }
+ public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null)
+ : base(
+ id => id.Value,
+ value => new PLACEHOLDERID(value),
+ mappingHints
+ ) { }
+ }
+
+ public partial class PLACEHOLDERIDNewtonsoftJsonConverter : global::Newtonsoft.Json.JsonConverter
+ {
+ public override bool CanConvert(global::System.Type objectType)
+ {
+ return objectType == typeof(PLACEHOLDERID);
+ }
+
+ public override void WriteJson(global::Newtonsoft.Json.JsonWriter writer, object? value, global::Newtonsoft.Json.JsonSerializer serializer)
+ {
+ serializer.Serialize(writer, value is PLACEHOLDERID id ? id.Value : null);
+ }
+
+ public override object? ReadJson(global::Newtonsoft.Json.JsonReader reader, global::System.Type objectType, object? existingValue, global::Newtonsoft.Json.JsonSerializer serializer)
+ {
+ var guid = serializer.Deserialize(reader);
+ return guid.HasValue ? new PLACEHOLDERID(guid.Value) : null;
+ }
+ }
+ }
\ No newline at end of file
diff --git a/src/StronglyTypedIds.Templates/guid-newtonsoftjson.typedid b/src/StronglyTypedIds.Templates/guid-newtonsoftjson.typedid
new file mode 100644
index 000000000..8fae4b82a
--- /dev/null
+++ b/src/StronglyTypedIds.Templates/guid-newtonsoftjson.typedid
@@ -0,0 +1,22 @@
+ [global::Newtonsoft.Json.JsonConverter(typeof(PLACEHOLDERIDNewtonsoftJsonConverter))]
+ partial struct PLACEHOLDERID
+ {
+ public partial class PLACEHOLDERIDNewtonsoftJsonConverter : global::Newtonsoft.Json.JsonConverter
+ {
+ public override bool CanConvert(global::System.Type objectType)
+ {
+ return objectType == typeof(PLACEHOLDERID);
+ }
+
+ public override void WriteJson(global::Newtonsoft.Json.JsonWriter writer, object? value, global::Newtonsoft.Json.JsonSerializer serializer)
+ {
+ serializer.Serialize(writer, value is PLACEHOLDERID id ? id.Value : null);
+ }
+
+ public override object? ReadJson(global::Newtonsoft.Json.JsonReader reader, global::System.Type objectType, object? existingValue, global::Newtonsoft.Json.JsonSerializer serializer)
+ {
+ var guid = serializer.Deserialize(reader);
+ return guid.HasValue ? new PLACEHOLDERID(guid.Value) : null;
+ }
+ }
+ }
\ No newline at end of file
diff --git a/src/StronglyTypedIds.Templates/int-dapper.typedid b/src/StronglyTypedIds.Templates/int-dapper.typedid
new file mode 100644
index 000000000..277a4e1f1
--- /dev/null
+++ b/src/StronglyTypedIds.Templates/int-dapper.typedid
@@ -0,0 +1,21 @@
+ partial struct PLACEHOLDERID
+ {
+ public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler
+ {
+ public override void SetValue(global::System.Data.IDbDataParameter parameter, PLACEHOLDERID value)
+ {
+ parameter.Value = value.Value;
+ }
+
+ public override PLACEHOLDERID Parse(object value)
+ {
+ return value switch
+ {
+ int intValue => new PLACEHOLDERID(intValue),
+ long longValue when longValue < int.MaxValue => new PLACEHOLDERID((int)longValue),
+ string stringValue when !string.IsNullOrEmpty(stringValue) && int.TryParse(stringValue, out var result) => new PLACEHOLDERID(result),
+ _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to PLACEHOLDERID"),
+ };
+ }
+ }
+ }
\ No newline at end of file
diff --git a/src/StronglyTypedIds.Templates/int-efcore.typedid b/src/StronglyTypedIds.Templates/int-efcore.typedid
new file mode 100644
index 000000000..c1f8fb3c6
--- /dev/null
+++ b/src/StronglyTypedIds.Templates/int-efcore.typedid
@@ -0,0 +1,13 @@
+ partial struct PLACEHOLDERID
+ {
+ public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter
+ {
+ public EfCoreValueConverter() : this(null) { }
+ public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null)
+ : base(
+ id => id.Value,
+ value => new PLACEHOLDERID(value),
+ mappingHints
+ ) { }
+ }
+ }
\ No newline at end of file
diff --git a/src/StronglyTypedIds.Templates/int-full.typedid b/src/StronglyTypedIds.Templates/int-full.typedid
new file mode 100644
index 000000000..7fb419868
--- /dev/null
+++ b/src/StronglyTypedIds.Templates/int-full.typedid
@@ -0,0 +1,250 @@
+ [global::System.ComponentModel.TypeConverter(typeof(PLACEHOLDERIDTypeConverter))]
+ [global::System.Text.Json.Serialization.JsonConverter(typeof(PLACEHOLDERIDSystemTextJsonConverter))]
+ [global::Newtonsoft.Json.JsonConverter(typeof(PLACEHOLDERIDNewtonsoftJsonConverter))]
+ partial struct PLACEHOLDERID :
+#if NET6_0_OR_GREATER
+ global::System.ISpanFormattable,
+#endif
+#if NET7_0_OR_GREATER
+ global::System.IParsable, global::System.ISpanParsable,
+#endif
+ global::System.IComparable, global::System.IEquatable, global::System.IFormattable
+ {
+ public int Value { get; }
+
+ public PLACEHOLDERID(int value)
+ {
+ Value = value;
+ }
+
+ public static readonly PLACEHOLDERID Empty = new PLACEHOLDERID(0);
+
+ ///
+ public bool Equals(PLACEHOLDERID other) => this.Value.Equals(other.Value);
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ return obj is PLACEHOLDERID other && Equals(other);
+ }
+
+ public override int GetHashCode() => Value.GetHashCode();
+
+ public override string ToString() => Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture);
+
+ public static bool operator ==(PLACEHOLDERID a, PLACEHOLDERID b) => a.Equals(b);
+ public static bool operator !=(PLACEHOLDERID a, PLACEHOLDERID b) => !(a == b);
+ public static bool operator > (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) > 0;
+ public static bool operator < (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) < 0;
+ public static bool operator >= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) >= 0;
+ public static bool operator <= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) <= 0;
+
+ ///
+ public int CompareTo(PLACEHOLDERID other) => Value.CompareTo(other.Value);
+
+ public partial class PLACEHOLDERIDTypeConverter : global::System.ComponentModel.TypeConverter
+ {
+ public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType)
+ {
+ return sourceType == typeof(int) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
+ }
+
+ public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value)
+ {
+ return value switch
+ {
+ int intValue => new PLACEHOLDERID(intValue),
+ string stringValue when !string.IsNullOrEmpty(stringValue) && int.TryParse(stringValue, out var result) => new PLACEHOLDERID(result),
+ _ => base.ConvertFrom(context, culture, value),
+ };
+ }
+
+ public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType)
+ {
+ return sourceType == typeof(int) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType);
+ }
+
+ public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType)
+ {
+ if (value is PLACEHOLDERID idValue)
+ {
+ if (destinationType == typeof(int))
+ {
+ return idValue.Value;
+ }
+
+ if (destinationType == typeof(string))
+ {
+ return idValue.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture);
+ }
+ }
+
+ return base.ConvertTo(context, culture, value, destinationType);
+ }
+ }
+
+ public partial class PLACEHOLDERIDSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter
+ {
+ public override bool CanConvert(global::System.Type typeToConvert)
+ => typeToConvert == typeof(int) || typeToConvert == typeof(string) || base.CanConvert(typeToConvert);
+
+ public override PLACEHOLDERID Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
+ => new (reader.GetInt32());
+
+ public override void Write(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options)
+ => writer.WriteNumberValue(value.Value);
+
+#if NET6_0_OR_GREATER
+ public override PLACEHOLDERID ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
+ => new(int.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the PLACEHOLDERID property was null")));
+
+ public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options)
+ => writer.WritePropertyName(value.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture));
+#endif
+ }
+
+ public static PLACEHOLDERID Parse(string input)
+ => new(int.Parse(input));
+
+#if NET7_0_OR_GREATER
+ ///
+ public static PLACEHOLDERID Parse(string input, global::System.IFormatProvider? provider)
+ => new(int.Parse(input, provider));
+
+ ///
+ public static bool TryParse(
+ [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input,
+ global::System.IFormatProvider? provider,
+ out PLACEHOLDERID result)
+ {
+ if (input is null)
+ {
+ result = default;
+ return false;
+ }
+
+ if (int.TryParse(input, provider, out var value))
+ {
+ result = new(value);
+ return true;
+ }
+
+ result = default;
+ return false;
+ }
+#endif
+
+ ///
+ public string ToString(
+#if NET7_0_OR_GREATER
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)]
+#endif
+ string? format,
+ global::System.IFormatProvider? formatProvider)
+ => Value.ToString(format, formatProvider);
+
+#if NETCOREAPP2_1_OR_GREATER
+ public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input)
+ => new(int.Parse(input));
+#endif
+
+#if NET6_0_OR_GREATER
+#if NET7_0_OR_GREATER
+ ///
+#endif
+ public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider)
+#if NET7_0_OR_GREATER
+ => new(int.Parse(input, provider));
+#else
+ => new(int.Parse(input));
+#endif
+
+#if NET7_0_OR_GREATER
+ ///
+#endif
+ public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out PLACEHOLDERID result)
+ {
+#if NET7_0_OR_GREATER
+ if (int.TryParse(input, provider, out var guid))
+#else
+ if (int.TryParse(input, out var guid))
+#endif
+ {
+ result = new(guid);
+ return true;
+ }
+
+ result = default;
+ return false;
+ }
+
+ ///
+ public bool TryFormat(
+ global::System.Span destination,
+ out int charsWritten,
+#if NET7_0_OR_GREATER
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)]
+#endif
+ global::System.ReadOnlySpan format,
+ global::System.IFormatProvider? provider)
+ => Value.TryFormat(destination, out charsWritten, format);
+
+ ///
+ public bool TryFormat(
+ global::System.Span destination,
+ out int charsWritten,
+#if NET7_0_OR_GREATER
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)]
+#endif
+ global::System.ReadOnlySpan format = default)
+ => Value.TryFormat(destination, out charsWritten, format);
+#endif
+
+ public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler
+ {
+ public override void SetValue(global::System.Data.IDbDataParameter parameter, PLACEHOLDERID value)
+ {
+ parameter.Value = value.Value;
+ }
+
+ public override PLACEHOLDERID Parse(object value)
+ {
+ return value switch
+ {
+ int intValue => new PLACEHOLDERID(intValue),
+ long longValue when longValue < int.MaxValue => new PLACEHOLDERID((int)longValue),
+ string stringValue when !string.IsNullOrEmpty(stringValue) && int.TryParse(stringValue, out var result) => new PLACEHOLDERID(result),
+ _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to PLACEHOLDERID"),
+ };
+ }
+ }
+
+ public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter
+ {
+ public EfCoreValueConverter() : this(null) { }
+ public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null)
+ : base(
+ id => id.Value,
+ value => new PLACEHOLDERID(value),
+ mappingHints
+ ) { }
+ }
+
+ public partial class PLACEHOLDERIDNewtonsoftJsonConverter : global::Newtonsoft.Json.JsonConverter
+ {
+ public override bool CanConvert(global::System.Type objectType)
+ {
+ return objectType == typeof(PLACEHOLDERID);
+ }
+
+ public override void WriteJson(global::Newtonsoft.Json.JsonWriter writer, object? value, global::Newtonsoft.Json.JsonSerializer serializer)
+ {
+ serializer.Serialize(writer, value is PLACEHOLDERID id ? id.Value : null);
+ }
+
+ public override object? ReadJson(global::Newtonsoft.Json.JsonReader reader, global::System.Type objectType, object? existingValue, global::Newtonsoft.Json.JsonSerializer serializer)
+ {
+ var result = serializer.Deserialize(reader);
+ return result.HasValue ? new PLACEHOLDERID(result.Value) : null;
+ }
+ }
+ }
\ No newline at end of file
diff --git a/src/StronglyTypedIds.Templates/int-newtonsoftjson.typedid b/src/StronglyTypedIds.Templates/int-newtonsoftjson.typedid
new file mode 100644
index 000000000..22de7b015
--- /dev/null
+++ b/src/StronglyTypedIds.Templates/int-newtonsoftjson.typedid
@@ -0,0 +1,22 @@
+ [global::Newtonsoft.Json.JsonConverter(typeof(PLACEHOLDERIDNewtonsoftJsonConverter))]
+ partial struct PLACEHOLDERID
+ {
+ public partial class PLACEHOLDERIDNewtonsoftJsonConverter : global::Newtonsoft.Json.JsonConverter
+ {
+ public override bool CanConvert(global::System.Type objectType)
+ {
+ return objectType == typeof(PLACEHOLDERID);
+ }
+
+ public override void WriteJson(global::Newtonsoft.Json.JsonWriter writer, object? value, global::Newtonsoft.Json.JsonSerializer serializer)
+ {
+ serializer.Serialize(writer, value is PLACEHOLDERID id ? id.Value : null);
+ }
+
+ public override object? ReadJson(global::Newtonsoft.Json.JsonReader reader, global::System.Type objectType, object? existingValue, global::Newtonsoft.Json.JsonSerializer serializer)
+ {
+ var result = serializer.Deserialize(reader);
+ return result.HasValue ? new PLACEHOLDERID(result.Value) : null;
+ }
+ }
+ }
\ No newline at end of file
diff --git a/src/StronglyTypedIds.Templates/long-dapper.typedid b/src/StronglyTypedIds.Templates/long-dapper.typedid
new file mode 100644
index 000000000..3310653e6
--- /dev/null
+++ b/src/StronglyTypedIds.Templates/long-dapper.typedid
@@ -0,0 +1,22 @@
+ partial struct PLACEHOLDERID
+ {
+ public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler
+ {
+ public override void SetValue(global::System.Data.IDbDataParameter parameter, PLACEHOLDERID value)
+ {
+ parameter.Value = value.Value;
+ }
+
+ public override PLACEHOLDERID Parse(object value)
+ {
+ return value switch
+ {
+ long longValue => new PLACEHOLDERID(longValue),
+ int intValue => new PLACEHOLDERID(intValue),
+ short shortValue => new PLACEHOLDERID(shortValue),
+ string stringValue when !string.IsNullOrEmpty(stringValue) && long.TryParse(stringValue, out var result) => new PLACEHOLDERID(result),
+ _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to PLACEHOLDERID"),
+ };
+ }
+ }
+ }
\ No newline at end of file
diff --git a/src/StronglyTypedIds.Templates/long-efcore.typedid b/src/StronglyTypedIds.Templates/long-efcore.typedid
new file mode 100644
index 000000000..ef88f8b7d
--- /dev/null
+++ b/src/StronglyTypedIds.Templates/long-efcore.typedid
@@ -0,0 +1,13 @@
+ partial struct PLACEHOLDERID
+ {
+ public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter
+ {
+ public EfCoreValueConverter() : this(null) { }
+ public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null)
+ : base(
+ id => id.Value,
+ value => new PLACEHOLDERID(value),
+ mappingHints
+ ) { }
+ }
+ }
\ No newline at end of file
diff --git a/src/StronglyTypedIds.Templates/long-full.typedid b/src/StronglyTypedIds.Templates/long-full.typedid
new file mode 100644
index 000000000..616e8a259
--- /dev/null
+++ b/src/StronglyTypedIds.Templates/long-full.typedid
@@ -0,0 +1,251 @@
+ [global::System.ComponentModel.TypeConverter(typeof(PLACEHOLDERIDTypeConverter))]
+ [global::System.Text.Json.Serialization.JsonConverter(typeof(PLACEHOLDERIDSystemTextJsonConverter))]
+ [global::Newtonsoft.Json.JsonConverter(typeof(PLACEHOLDERIDNewtonsoftJsonConverter))]
+ partial struct PLACEHOLDERID :
+#if NET6_0_OR_GREATER
+ global::System.ISpanFormattable,
+#endif
+#if NET7_0_OR_GREATER
+ global::System.IParsable, global::System.ISpanParsable,
+#endif
+ global::System.IComparable, global::System.IEquatable, global::System.IFormattable
+ {
+ public long Value { get; }
+
+ public PLACEHOLDERID(long value)
+ {
+ Value = value;
+ }
+
+ public static readonly PLACEHOLDERID Empty = new PLACEHOLDERID(0);
+
+ ///
+ public bool Equals(PLACEHOLDERID other) => this.Value.Equals(other.Value);
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ return obj is PLACEHOLDERID other && Equals(other);
+ }
+
+ public override int GetHashCode() => Value.GetHashCode();
+
+ public override string ToString() => Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture);
+
+ public static bool operator ==(PLACEHOLDERID a, PLACEHOLDERID b) => a.Equals(b);
+ public static bool operator !=(PLACEHOLDERID a, PLACEHOLDERID b) => !(a == b);
+ public static bool operator > (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) > 0;
+ public static bool operator < (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) < 0;
+ public static bool operator >= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) >= 0;
+ public static bool operator <= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) <= 0;
+
+ ///
+ public int CompareTo(PLACEHOLDERID other) => Value.CompareTo(other.Value);
+
+ public partial class PLACEHOLDERIDTypeConverter : global::System.ComponentModel.TypeConverter
+ {
+ public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType)
+ {
+ return sourceType == typeof(long) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
+ }
+
+ public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value)
+ {
+ return value switch
+ {
+ long intValue => new PLACEHOLDERID(intValue),
+ string stringValue when !string.IsNullOrEmpty(stringValue) && long.TryParse(stringValue, out var result) => new PLACEHOLDERID(result),
+ _ => base.ConvertFrom(context, culture, value),
+ };
+ }
+
+ public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType)
+ {
+ return sourceType == typeof(long) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType);
+ }
+
+ public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType)
+ {
+ if (value is PLACEHOLDERID idValue)
+ {
+ if (destinationType == typeof(long))
+ {
+ return idValue.Value;
+ }
+
+ if (destinationType == typeof(string))
+ {
+ return idValue.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture);
+ }
+ }
+
+ return base.ConvertTo(context, culture, value, destinationType);
+ }
+ }
+
+ public partial class PLACEHOLDERIDSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter
+ {
+ public override bool CanConvert(global::System.Type typeToConvert)
+ => typeToConvert == typeof(long) || typeToConvert == typeof(string) || base.CanConvert(typeToConvert);
+
+ public override PLACEHOLDERID Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
+ => new (reader.GetInt32());
+
+ public override void Write(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options)
+ => writer.WriteNumberValue(value.Value);
+
+#if NET6_0_OR_GREATER
+ public override PLACEHOLDERID ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
+ => new(long.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the PLACEHOLDERID property was null")));
+
+ public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options)
+ => writer.WritePropertyName(value.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture));
+#endif
+ }
+
+ public static PLACEHOLDERID Parse(string input)
+ => new(long.Parse(input));
+
+#if NET7_0_OR_GREATER
+ ///
+ public static PLACEHOLDERID Parse(string input, global::System.IFormatProvider? provider)
+ => new(long.Parse(input, provider));
+
+ ///
+ public static bool TryParse(
+ [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input,
+ global::System.IFormatProvider? provider,
+ out PLACEHOLDERID result)
+ {
+ if (input is null)
+ {
+ result = default;
+ return false;
+ }
+
+ if (long.TryParse(input, provider, out var value))
+ {
+ result = new(value);
+ return true;
+ }
+
+ result = default;
+ return false;
+ }
+#endif
+
+ ///
+ public string ToString(
+#if NET7_0_OR_GREATER
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)]
+#endif
+ string? format,
+ global::System.IFormatProvider? formatProvider)
+ => Value.ToString(format, formatProvider);
+
+#if NETCOREAPP2_1_OR_GREATER
+ public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input)
+ => new(long.Parse(input));
+#endif
+
+#if NET6_0_OR_GREATER
+#if NET7_0_OR_GREATER
+ ///
+#endif
+ public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider)
+#if NET7_0_OR_GREATER
+ => new(long.Parse(input, provider));
+#else
+ => new(long.Parse(input));
+#endif
+
+#if NET7_0_OR_GREATER
+ ///
+#endif
+ public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out PLACEHOLDERID result)
+ {
+#if NET7_0_OR_GREATER
+ if (long.TryParse(input, provider, out var guid))
+#else
+ if (long.TryParse(input, out var guid))
+#endif
+ {
+ result = new(guid);
+ return true;
+ }
+
+ result = default;
+ return false;
+ }
+
+ ///
+ public bool TryFormat(
+ global::System.Span destination,
+ out int charsWritten,
+#if NET7_0_OR_GREATER
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)]
+#endif
+ global::System.ReadOnlySpan format,
+ global::System.IFormatProvider? provider)
+ => Value.TryFormat(destination, out charsWritten, format);
+
+ ///
+ public bool TryFormat(
+ global::System.Span destination,
+ out int charsWritten,
+#if NET7_0_OR_GREATER
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)]
+#endif
+ global::System.ReadOnlySpan format = default)
+ => Value.TryFormat(destination, out charsWritten, format);
+#endif
+
+ public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler
+ {
+ public override void SetValue(global::System.Data.IDbDataParameter parameter, PLACEHOLDERID value)
+ {
+ parameter.Value = value.Value;
+ }
+
+ public override PLACEHOLDERID Parse(object value)
+ {
+ return value switch
+ {
+ long longValue => new PLACEHOLDERID(longValue),
+ int intValue => new PLACEHOLDERID(intValue),
+ short shortValue => new PLACEHOLDERID(shortValue),
+ string stringValue when !string.IsNullOrEmpty(stringValue) && long.TryParse(stringValue, out var result) => new PLACEHOLDERID(result),
+ _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to PLACEHOLDERID"),
+ };
+ }
+ }
+
+ public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter
+ {
+ public EfCoreValueConverter() : this(null) { }
+ public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null)
+ : base(
+ id => id.Value,
+ value => new PLACEHOLDERID(value),
+ mappingHints
+ ) { }
+ }
+
+ public partial class PLACEHOLDERIDNewtonsoftJsonConverter : global::Newtonsoft.Json.JsonConverter
+ {
+ public override bool CanConvert(global::System.Type objectType)
+ {
+ return objectType == typeof(PLACEHOLDERID);
+ }
+
+ public override void WriteJson(global::Newtonsoft.Json.JsonWriter writer, object? value, global::Newtonsoft.Json.JsonSerializer serializer)
+ {
+ serializer.Serialize(writer, value is PLACEHOLDERID id ? id.Value : null);
+ }
+
+ public override object? ReadJson(global::Newtonsoft.Json.JsonReader reader, global::System.Type objectType, object? existingValue, global::Newtonsoft.Json.JsonSerializer serializer)
+ {
+ var result = serializer.Deserialize(reader);
+ return result.HasValue ? new PLACEHOLDERID(result.Value) : null;
+ }
+ }
+ }
\ No newline at end of file
diff --git a/src/StronglyTypedIds.Templates/long-newtonsoftjson.typedid b/src/StronglyTypedIds.Templates/long-newtonsoftjson.typedid
new file mode 100644
index 000000000..ba37cc152
--- /dev/null
+++ b/src/StronglyTypedIds.Templates/long-newtonsoftjson.typedid
@@ -0,0 +1,22 @@
+ [global::Newtonsoft.Json.JsonConverter(typeof(PLACEHOLDERIDNewtonsoftJsonConverter))]
+ partial struct PLACEHOLDERID
+ {
+ public partial class PLACEHOLDERIDNewtonsoftJsonConverter : global::Newtonsoft.Json.JsonConverter
+ {
+ public override bool CanConvert(global::System.Type objectType)
+ {
+ return objectType == typeof(PLACEHOLDERID);
+ }
+
+ public override void WriteJson(global::Newtonsoft.Json.JsonWriter writer, object? value, global::Newtonsoft.Json.JsonSerializer serializer)
+ {
+ serializer.Serialize(writer, value is PLACEHOLDERID id ? id.Value : null);
+ }
+
+ public override object? ReadJson(global::Newtonsoft.Json.JsonReader reader, global::System.Type objectType, object? existingValue, global::Newtonsoft.Json.JsonSerializer serializer)
+ {
+ var result = serializer.Deserialize(reader);
+ return result.HasValue ? new PLACEHOLDERID(result.Value) : null;
+ }
+ }
+ }
\ No newline at end of file
diff --git a/src/StronglyTypedIds.Templates/newid-full.typedid b/src/StronglyTypedIds.Templates/newid-full.typedid
new file mode 100644
index 000000000..d55f97530
--- /dev/null
+++ b/src/StronglyTypedIds.Templates/newid-full.typedid
@@ -0,0 +1,257 @@
+ [global::System.ComponentModel.TypeConverter(typeof(PLACEHOLDERIDTypeConverter))]
+ [global::System.Text.Json.Serialization.JsonConverter(typeof(PLACEHOLDERIDSystemTextJsonConverter))]
+ [global::Newtonsoft.Json.JsonConverter(typeof(PLACEHOLDERIDNewtonsoftJsonConverter))]
+ partial struct PLACEHOLDERID :
+#if NET6_0_OR_GREATER
+ global::System.ISpanFormattable,
+#endif
+#if NET7_0_OR_GREATER
+ global::System.IParsable, global::System.ISpanParsable,
+#endif
+ global::System.IComparable, global::System.IEquatable, global::System.IFormattable
+ {
+ public global::MassTransit.NewId Value { get; }
+
+ public PLACEHOLDERID(global::MassTransit.NewId value)
+ {
+ Value = value;
+ }
+
+ public static PLACEHOLDERID New() => new PLACEHOLDERID(global::MassTransit.NewId.Next());
+ public static readonly PLACEHOLDERID Empty = new PLACEHOLDERID(global::MassTransit.NewId.Empty);
+
+ ///
+ public bool Equals(PLACEHOLDERID other) => this.Value.Equals(other.Value);
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ return obj is PLACEHOLDERID other && Equals(other);
+ }
+
+ public override int GetHashCode() => Value.GetHashCode();
+
+ public override string ToString() => Value.ToString();
+
+ public static bool operator ==(PLACEHOLDERID a, PLACEHOLDERID b) => a.Equals(b);
+ public static bool operator !=(PLACEHOLDERID a, PLACEHOLDERID b) => !(a == b);
+ public static bool operator > (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) > 0;
+ public static bool operator < (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) < 0;
+ public static bool operator >= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) >= 0;
+ public static bool operator <= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) <= 0;
+
+ ///
+ public int CompareTo(PLACEHOLDERID other) => Value.CompareTo(other.Value);
+
+ public partial class PLACEHOLDERIDTypeConverter : global::System.ComponentModel.TypeConverter
+ {
+ public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType)
+ {
+ return sourceType == typeof(System.Guid) || sourceType == typeof(global::MassTransit.NewId)
+ || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
+ }
+
+ public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value)
+ {
+ return value switch
+ {
+ global::MassTransit.NewId newIdValue => new PLACEHOLDERID(newIdValue),
+ global::System.Guid guidValue => new PLACEHOLDERID(global::MassTransit.NewId.FromGuid(guidValue)),
+ string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new PLACEHOLDERID(global::MassTransit.NewId.FromGuid(result)),
+ _ => base.ConvertFrom(context, culture, value),
+ };
+ }
+
+ public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType)
+ {
+ return sourceType == typeof(System.Guid) || sourceType == typeof(global::MassTransit.NewId)
+ || sourceType == typeof(string) || base.CanConvertTo(context, sourceType);
+ }
+
+ public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType)
+ {
+ if (value is PLACEHOLDERID idValue)
+ {
+ if (destinationType == typeof(global::MassTransit.NewId))
+ {
+ return idValue.Value;
+ }
+
+ if (destinationType == typeof(global::System.Guid))
+ {
+ return idValue.Value.ToGuid();
+ }
+
+ if (destinationType == typeof(string))
+ {
+ return idValue.Value.ToGuid().ToString();
+ }
+ }
+
+ return base.ConvertTo(context, culture, value, destinationType);
+ }
+ }
+
+ public partial class PLACEHOLDERIDSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter
+ {
+ public override bool CanConvert(global::System.Type typeToConvert)
+ => typeToConvert == typeof(string) || typeToConvert == typeof(global::System.Guid) || base.CanConvert(typeToConvert);
+
+ public override PLACEHOLDERID Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
+ => new (global::MassTransit.NewId.FromGuid(reader.GetGuid()));
+
+ public override void Write(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options)
+ => writer.WriteStringValue(value.Value.ToGuid());
+
+#if NET6_0_OR_GREATER
+ public override PLACEHOLDERID ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
+ => new(global::MassTransit.NewId.FromGuid(global::System.Guid.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the PLACEHOLDERID property was null"))));
+
+ public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options)
+ => writer.WritePropertyName(value.Value.ToGuid().ToString());
+#endif
+ }
+
+ public static PLACEHOLDERID Parse(string input)
+ => new(global::MassTransit.NewId.FromGuid(global::System.Guid.Parse(input)));
+
+#if NET7_0_OR_GREATER
+ ///
+ public static PLACEHOLDERID Parse(string input, global::System.IFormatProvider? provider)
+ => new(global::MassTransit.NewId.FromGuid(global::System.Guid.Parse(input, provider)));
+
+ ///
+ public static bool TryParse(
+ [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input,
+ global::System.IFormatProvider? provider,
+ out PLACEHOLDERID result)
+ {
+ if (input is null)
+ {
+ result = default;
+ return false;
+ }
+
+ if (global::System.Guid.TryParse(input, provider, out var guid))
+ {
+ result = new(global::MassTransit.NewId.FromGuid(guid));
+ return true;
+ }
+ else
+ {
+ result = default;
+ return false;
+ }
+ }
+#endif
+
+ ///
+ public string ToString(string? format, global::System.IFormatProvider? formatProvider)
+ => Value.ToGuid().ToString(format, formatProvider);
+
+#if NETCOREAPP2_1_OR_GREATER
+ public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input)
+ => new(global::MassTransit.NewId.FromGuid(global::System.Guid.Parse(input)));
+#endif
+
+#if NET6_0_OR_GREATER
+#if NET7_0_OR_GREATER
+ ///
+#endif
+ public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider)
+#if NET7_0_OR_GREATER
+ => new(global::MassTransit.NewId.FromGuid(global::System.Guid.Parse(input, provider)));
+#else
+ => new(global::MassTransit.NewId.FromGuid(global::System.Guid.Parse(input)));
+#endif
+
+#if NET7_0_OR_GREATER
+ ///
+#endif
+ public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out PLACEHOLDERID result)
+ {
+#if NET7_0_OR_GREATER
+ if (global::System.Guid.TryParse(input, provider, out var guid))
+#else
+ if (global::System.Guid.TryParse(input, out var guid))
+#endif
+ {
+ result = new(global::MassTransit.NewId.FromGuid(guid));
+ return true;
+ }
+ else
+ {
+ result = default;
+ return false;
+ }
+ }
+
+ ///
+ public bool TryFormat(
+ global::System.Span destination,
+ out int charsWritten,
+#if NET7_0_OR_GREATER
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)]
+#endif
+ global::System.ReadOnlySpan format,
+ global::System.IFormatProvider? provider)
+ => Value.ToGuid().TryFormat(destination, out charsWritten, format);
+
+ ///
+ public bool TryFormat(
+ global::System.Span destination,
+ out int charsWritten,
+#if NET7_0_OR_GREATER
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)]
+#endif
+ global::System.ReadOnlySpan format = default)
+ => Value.ToGuid().TryFormat(destination, out charsWritten, format);
+#endif
+
+ public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler
+ {
+ public override void SetValue(global::System.Data.IDbDataParameter parameter, PLACEHOLDERID value)
+ {
+ parameter.Value = value.Value.ToGuid();
+ }
+
+ public override PLACEHOLDERID Parse(object value)
+ {
+ return value switch
+ {
+ global::System.Guid guidValue => new PLACEHOLDERID(global::MassTransit.NewId.FromGuid(guidValue)),
+ string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new PLACEHOLDERID(global::MassTransit.NewId.FromGuid(result)),
+ _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to PLACEHOLDERID"),
+ };
+ }
+ }
+
+ public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter
+ {
+ public EfCoreValueConverter() : this(null) { }
+ public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null)
+ : base(
+ id => id.Value.ToGuid(),
+ value => new PLACEHOLDERID(global::MassTransit.NewId.FromGuid(value)),
+ mappingHints
+ ) { }
+ }
+
+ public partial class PLACEHOLDERIDNewtonsoftJsonConverter : global::Newtonsoft.Json.JsonConverter
+ {
+ public override bool CanConvert(global::System.Type objectType)
+ {
+ return objectType == typeof(PLACEHOLDERID);
+ }
+
+ public override void WriteJson(global::Newtonsoft.Json.JsonWriter writer, object? value, global::Newtonsoft.Json.JsonSerializer serializer)
+ {
+ serializer.Serialize(writer, value is PLACEHOLDERID id ? id.Value : null);
+ }
+
+ public override object? ReadJson(global::Newtonsoft.Json.JsonReader reader, global::System.Type objectType, object? existingValue, global::Newtonsoft.Json.JsonSerializer serializer)
+ {
+ var guid = serializer.Deserialize(reader);
+ return guid.HasValue ? new PLACEHOLDERID(global::MassTransit.NewId.FromGuid(guid.Value)) : null;
+ }
+ }
+ }
\ No newline at end of file
diff --git a/src/StronglyTypedIds.Templates/nullablestring-full.typedid b/src/StronglyTypedIds.Templates/nullablestring-full.typedid
new file mode 100644
index 000000000..6c06d57c1
--- /dev/null
+++ b/src/StronglyTypedIds.Templates/nullablestring-full.typedid
@@ -0,0 +1,246 @@
+ [global::System.ComponentModel.TypeConverter(typeof(PLACEHOLDERIDTypeConverter))]
+ [global::System.Text.Json.Serialization.JsonConverter(typeof(PLACEHOLDERIDSystemTextJsonConverter))]
+ [global::Newtonsoft.Json.JsonConverter(typeof(PLACEHOLDERIDNewtonsoftJsonConverter))]
+ partial struct PLACEHOLDERID :
+#if NET6_0_OR_GREATER
+ global::System.ISpanFormattable,
+#endif
+#if NET7_0_OR_GREATER
+ global::System.IParsable, global::System.ISpanParsable,
+#endif
+ global::System.IComparable, global::System.IEquatable, global::System.IFormattable
+ {
+ public string? Value { get; }
+
+ public PLACEHOLDERID(string? value)
+ {
+ Value = value;
+ }
+
+ public static readonly PLACEHOLDERID Empty = new PLACEHOLDERID(string.Empty);
+
+ ///
+ public bool Equals(PLACEHOLDERID other)
+ => (Value, other.Value) switch
+ {
+ (null, null) => true,
+ (null, _) => false,
+ (_, null) => false,
+ (_, _) => Value.Equals(other.Value, global::System.StringComparison.Ordinal),
+ };
+
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ return obj is PLACEHOLDERID other && Equals(other);
+ }
+
+ public override int GetHashCode() => Value?.GetHashCode() ?? 0;
+
+ public override string? ToString() => Value;
+
+ public static bool operator ==(PLACEHOLDERID a, PLACEHOLDERID b) => a.Equals(b);
+ public static bool operator !=(PLACEHOLDERID a, PLACEHOLDERID b) => !(a == b);
+ public static bool operator > (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) > 0;
+ public static bool operator < (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) < 0;
+ public static bool operator >= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) >= 0;
+ public static bool operator <= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) <= 0;
+
+ ///
+ public int CompareTo(PLACEHOLDERID other)
+ => (Value, other.Value) switch
+ {
+ (null, null) => 0,
+ (null, _) => -1,
+ (_, null) => 1,
+ (_, _) => string.CompareOrdinal(Value, other.Value),
+ };
+
+ public partial class PLACEHOLDERIDTypeConverter : global::System.ComponentModel.TypeConverter
+ {
+ public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType)
+ {
+ return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
+ }
+
+ public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value)
+ => value switch
+ {
+ null => new PLACEHOLDERID(null),
+ string x => new PLACEHOLDERID(x),
+ _ => base.ConvertFrom(context, culture, value),
+ };
+
+ public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType)
+ {
+ return sourceType == typeof(string) || base.CanConvertTo(context, sourceType);
+ }
+
+ public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType)
+ {
+ if (value is PLACEHOLDERID idValue)
+ {
+ if (destinationType == typeof(string))
+ {
+ return idValue.Value;
+ }
+ }
+
+ return base.ConvertTo(context, culture, value, destinationType);
+ }
+ }
+
+ public partial class PLACEHOLDERIDSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter
+ {
+ public override bool CanConvert(global::System.Type typeToConvert)
+ => typeToConvert == typeof(string) || base.CanConvert(typeToConvert);
+
+ public override PLACEHOLDERID Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
+ => new (reader.GetString());
+
+ public override void Write(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options)
+ {
+ if (value.Value is null)
+ {
+ writer.WriteNullValue();
+ }
+ else
+ {
+ writer.WriteStringValue(value.Value);
+ }
+ }
+
+#if NET6_0_OR_GREATER
+ public override PLACEHOLDERID ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
+ => new(reader.GetString());
+
+ public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options)
+ => writer.WritePropertyName(value.Value ?? string.Empty);
+#endif
+ }
+
+ public static PLACEHOLDERID Parse(string input)
+ => new(input);
+
+#if NET7_0_OR_GREATER
+ ///
+ public static PLACEHOLDERID Parse(string input, global::System.IFormatProvider? provider)
+ => new(input);
+
+ ///
+ public static bool TryParse(
+ string? input,
+ global::System.IFormatProvider? provider,
+ out PLACEHOLDERID result)
+ {
+ result = new(input);
+ return true;
+ }
+#endif
+
+ ///
+ public string ToString(string? format, global::System.IFormatProvider? formatProvider)
+ => Value ?? string.Empty;
+
+#if NETCOREAPP2_1_OR_GREATER
+ public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input)
+ => new(input.ToString());
+#endif
+
+#if NET6_0_OR_GREATER
+#if NET7_0_OR_GREATER
+ ///
+#endif
+ public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider)
+ => new(input.ToString());
+
+#if NET7_0_OR_GREATER
+ ///
+#endif
+ public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out PLACEHOLDERID result)
+ {
+ result = new(input.ToString());
+ return true;
+ }
+
+ ///
+ public bool TryFormat(
+ global::System.Span destination,
+ out int charsWritten,
+ global::System.ReadOnlySpan format,
+ global::System.IFormatProvider? provider)
+ => TryFormat(destination, out charsWritten, format);
+
+ ///
+ public bool TryFormat(
+ global::System.Span destination,
+ out int charsWritten,
+ global::System.ReadOnlySpan format = default)
+ {
+ if (Value is not null && destination.Length > Value.Length)
+ {
+ global::System.MemoryExtensions.AsSpan(Value).CopyTo(destination);
+ charsWritten = Value.Length;
+ return true;
+ }
+
+ charsWritten = default;
+ return false;
+ }
+#endif
+
+ public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler
+ {
+ public override void SetValue(global::System.Data.IDbDataParameter parameter, PLACEHOLDERID value)
+ {
+ parameter.Value = value.Value;
+ }
+
+ public override PLACEHOLDERID Parse(object value)
+ {
+ return value switch
+ {
+ null => new PLACEHOLDERID(null),
+ System.DBNull => new PLACEHOLDERID(null),
+ string stringValue => new PLACEHOLDERID(stringValue),
+ _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to PLACEHOLDERID"),
+ };
+ }
+ }
+
+ public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter
+ {
+ public EfCoreValueConverter() : this(null) { }
+ public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null)
+ : base(
+ id => id.Value,
+ value => new PLACEHOLDERID(value),
+ mappingHints
+ ) { }
+ }
+
+ public partial class PLACEHOLDERIDNewtonsoftJsonConverter : global::Newtonsoft.Json.JsonConverter
+ {
+ public override bool CanConvert(global::System.Type objectType)
+ {
+ return objectType == typeof(PLACEHOLDERID);
+ }
+
+ public override void WriteJson(global::Newtonsoft.Json.JsonWriter writer, object? value, global::Newtonsoft.Json.JsonSerializer serializer)
+ {
+ serializer.Serialize(writer, value is PLACEHOLDERID id ? id.Value : null);
+ }
+
+ public override object? ReadJson(global::Newtonsoft.Json.JsonReader reader, global::System.Type objectType, object? existingValue, global::Newtonsoft.Json.JsonSerializer serializer)
+ {
+ if (objectType == typeof(PLACEHOLDERID?))
+ {
+ var value = serializer.Deserialize(reader);
+
+ return new PLACEHOLDERID(value);
+ }
+
+ return new PLACEHOLDERID(serializer.Deserialize(reader));
+ }
+ }
+ }
\ No newline at end of file
diff --git a/src/StronglyTypedIds.Templates/string-dapper.typedid b/src/StronglyTypedIds.Templates/string-dapper.typedid
new file mode 100644
index 000000000..4af050343
--- /dev/null
+++ b/src/StronglyTypedIds.Templates/string-dapper.typedid
@@ -0,0 +1,19 @@
+ partial struct PLACEHOLDERID
+ {
+ public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler
+ {
+ public override void SetValue(global::System.Data.IDbDataParameter parameter, PLACEHOLDERID value)
+ {
+ parameter.Value = value.Value;
+ }
+
+ public override PLACEHOLDERID Parse(object value)
+ {
+ return value switch
+ {
+ string stringValue => new PLACEHOLDERID(stringValue),
+ _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to PLACEHOLDERID"),
+ };
+ }
+ }
+ }
\ No newline at end of file
diff --git a/src/StronglyTypedIds.Templates/string-efcore.typedid b/src/StronglyTypedIds.Templates/string-efcore.typedid
new file mode 100644
index 000000000..6fd5fc403
--- /dev/null
+++ b/src/StronglyTypedIds.Templates/string-efcore.typedid
@@ -0,0 +1,13 @@
+ partial struct PLACEHOLDERID
+ {
+ public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter
+ {
+ public EfCoreValueConverter() : this(null) { }
+ public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null)
+ : base(
+ id => id.Value,
+ value => new PLACEHOLDERID(value),
+ mappingHints
+ ) { }
+ }
+ }
\ No newline at end of file
diff --git a/src/StronglyTypedIds.Templates/string-full.typedid b/src/StronglyTypedIds.Templates/string-full.typedid
new file mode 100644
index 000000000..be8e396f3
--- /dev/null
+++ b/src/StronglyTypedIds.Templates/string-full.typedid
@@ -0,0 +1,243 @@
+ [global::System.ComponentModel.TypeConverter(typeof(PLACEHOLDERIDTypeConverter))]
+ [global::System.Text.Json.Serialization.JsonConverter(typeof(PLACEHOLDERIDSystemTextJsonConverter))]
+ [global::Newtonsoft.Json.JsonConverter(typeof(PLACEHOLDERIDNewtonsoftJsonConverter))]
+ partial struct PLACEHOLDERID :
+#if NET6_0_OR_GREATER
+ global::System.ISpanFormattable,
+#endif
+#if NET7_0_OR_GREATER
+ global::System.IParsable, global::System.ISpanParsable,
+#endif
+ global::System.IComparable, global::System.IEquatable, global::System.IFormattable
+ {
+ public string Value { get; }
+
+ public PLACEHOLDERID(string value)
+ {
+ Value = value ?? throw new global::System.ArgumentNullException(nameof(value));
+ }
+
+ public static readonly PLACEHOLDERID Empty = new PLACEHOLDERID(string.Empty);
+
+ ///
+ public bool Equals(PLACEHOLDERID other)
+ => (Value, other.Value) switch
+ {
+ (null, null) => true,
+ (null, _) => false,
+ (_, null) => false,
+ (_, _) => Value.Equals(other.Value, global::System.StringComparison.Ordinal),
+ };
+
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ return obj is PLACEHOLDERID other && Equals(other);
+ }
+
+ public override int GetHashCode() => Value.GetHashCode();
+
+ public override string ToString() => Value;
+
+ public static bool operator ==(PLACEHOLDERID a, PLACEHOLDERID b) => a.Equals(b);
+ public static bool operator !=(PLACEHOLDERID a, PLACEHOLDERID b) => !(a == b);
+ public static bool operator > (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) > 0;
+ public static bool operator < (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) < 0;
+ public static bool operator >= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) >= 0;
+ public static bool operator <= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) <= 0;
+
+ ///
+ public int CompareTo(PLACEHOLDERID other)
+ => (Value, other.Value) switch
+ {
+ (null, null) => 0,
+ (null, _) => -1,
+ (_, null) => 1,
+ (_, _) => string.CompareOrdinal(Value, other.Value),
+ };
+
+ public partial class PLACEHOLDERIDTypeConverter : global::System.ComponentModel.TypeConverter
+ {
+ public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType)
+ {
+ return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
+ }
+
+ public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value)
+ {
+ if (value is string stringValue)
+ {
+ return new PLACEHOLDERID(stringValue);
+ }
+
+ return base.ConvertFrom(context, culture, value);
+ }
+
+ public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType)
+ {
+ return sourceType == typeof(string) || base.CanConvertTo(context, sourceType);
+ }
+
+ public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType)
+ {
+ if (value is PLACEHOLDERID idValue)
+ {
+ if (destinationType == typeof(string))
+ {
+ return idValue.Value;
+ }
+ }
+
+ return base.ConvertTo(context, culture, value, destinationType);
+ }
+ }
+
+ public partial class PLACEHOLDERIDSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter
+ {
+ public override bool CanConvert(global::System.Type typeToConvert)
+ => typeToConvert == typeof(string) || base.CanConvert(typeToConvert);
+
+ public override PLACEHOLDERID Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
+ => new (reader.GetString()!);
+
+ public override void Write(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options)
+ => writer.WriteStringValue(value.Value);
+
+#if NET6_0_OR_GREATER
+ public override PLACEHOLDERID ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
+ => new(reader.GetString() ?? throw new global::System.FormatException("The string for the PLACEHOLDERID property was null"));
+
+ public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options)
+ => writer.WritePropertyName(value.Value);
+#endif
+ }
+
+ public static PLACEHOLDERID Parse(string input)
+ => new(input);
+
+#if NET7_0_OR_GREATER
+ ///
+ public static PLACEHOLDERID Parse(string input, global::System.IFormatProvider? provider)
+ => new(input);
+
+ ///
+ public static bool TryParse(
+ [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input,
+ global::System.IFormatProvider? provider,
+ out PLACEHOLDERID result)
+ {
+ if (input is null)
+ {
+ result = default;
+ return false;
+ }
+
+ result = new(input);
+ return true;
+ }
+#endif
+
+ ///
+ public string ToString(string? format, global::System.IFormatProvider? formatProvider)
+ => Value;
+
+#if NETCOREAPP2_1_OR_GREATER
+ public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input)
+ => new(input.ToString());
+#endif
+
+#if NET6_0_OR_GREATER
+#if NET7_0_OR_GREATER
+ ///
+#endif
+ public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider)
+ => new(input.ToString());
+
+#if NET7_0_OR_GREATER
+ ///
+#endif
+ public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out PLACEHOLDERID result)
+ {
+ result = new(input.ToString());
+ return true;
+ }
+
+ ///
+ public bool TryFormat(
+ global::System.Span destination,
+ out int charsWritten,
+ global::System.ReadOnlySpan format,
+ global::System.IFormatProvider? provider)
+ => TryFormat(destination, out charsWritten, format);
+
+ ///
+ public bool TryFormat(
+ global::System.Span destination,
+ out int charsWritten,
+ global::System.ReadOnlySpan format = default)
+ {
+ if (destination.Length > Value.Length)
+ {
+ global::System.MemoryExtensions.AsSpan(Value).CopyTo(destination);
+ charsWritten = Value.Length;
+ return true;
+ }
+
+ charsWritten = default;
+ return false;
+ }
+#endif
+
+ public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler
+ {
+ public override void SetValue(global::System.Data.IDbDataParameter parameter, PLACEHOLDERID value)
+ {
+ parameter.Value = value.Value;
+ }
+
+ public override PLACEHOLDERID Parse(object value)
+ {
+ return value switch
+ {
+ string stringValue => new PLACEHOLDERID(stringValue),
+ _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to PLACEHOLDERID"),
+ };
+ }
+ }
+
+ public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter
+ {
+ public EfCoreValueConverter() : this(null) { }
+ public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null)
+ : base(
+ id => id.Value,
+ value => new PLACEHOLDERID(value),
+ mappingHints
+ ) { }
+ }
+
+ public partial class PLACEHOLDERIDNewtonsoftJsonConverter : global::Newtonsoft.Json.JsonConverter
+ {
+ public override bool CanConvert(global::System.Type objectType)
+ {
+ return objectType == typeof(PLACEHOLDERID);
+ }
+
+ public override void WriteJson(global::Newtonsoft.Json.JsonWriter writer, object? value, global::Newtonsoft.Json.JsonSerializer serializer)
+ {
+ serializer.Serialize(writer, value is PLACEHOLDERID id ? id.Value : null);
+ }
+
+ public override object? ReadJson(global::Newtonsoft.Json.JsonReader reader, global::System.Type objectType, object? existingValue, global::Newtonsoft.Json.JsonSerializer serializer)
+ {
+ if (objectType == typeof(PLACEHOLDERID?))
+ {
+ var value = serializer.Deserialize(reader);
+
+ return value is null ? null : new PLACEHOLDERID(value);
+ }
+
+ return new PLACEHOLDERID(serializer.Deserialize(reader)!);
+ }
+ }
+ }
\ No newline at end of file
diff --git a/src/StronglyTypedIds.Templates/string-newtonsoftjson.typedid b/src/StronglyTypedIds.Templates/string-newtonsoftjson.typedid
new file mode 100644
index 000000000..4711a24ec
--- /dev/null
+++ b/src/StronglyTypedIds.Templates/string-newtonsoftjson.typedid
@@ -0,0 +1,28 @@
+ [global::Newtonsoft.Json.JsonConverter(typeof(PLACEHOLDERIDNewtonsoftJsonConverter))]
+ partial struct PLACEHOLDERID
+ {
+ public partial class PLACEHOLDERIDNewtonsoftJsonConverter : global::Newtonsoft.Json.JsonConverter
+ {
+ public override bool CanConvert(global::System.Type objectType)
+ {
+ return objectType == typeof(PLACEHOLDERID);
+ }
+
+ public override void WriteJson(global::Newtonsoft.Json.JsonWriter writer, object? value, global::Newtonsoft.Json.JsonSerializer serializer)
+ {
+ serializer.Serialize(writer, value is PLACEHOLDERID id ? id.Value : null);
+ }
+
+ public override object? ReadJson(global::Newtonsoft.Json.JsonReader reader, global::System.Type objectType, object? existingValue, global::Newtonsoft.Json.JsonSerializer serializer)
+ {
+ if (objectType == typeof(PLACEHOLDERID?))
+ {
+ var value = serializer.Deserialize(reader);
+
+ return value is null ? null : new PLACEHOLDERID(value);
+ }
+
+ return new PLACEHOLDERID(serializer.Deserialize(reader)!);
+ }
+ }
+ }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/DiagnosticInfo.cs b/src/StronglyTypedIds/DiagnosticInfo.cs
new file mode 100644
index 000000000..ce57b8bf3
--- /dev/null
+++ b/src/StronglyTypedIds/DiagnosticInfo.cs
@@ -0,0 +1,19 @@
+using Microsoft.CodeAnalysis;
+
+namespace StronglyTypedIds;
+
+internal sealed record DiagnosticInfo
+{
+ public DiagnosticInfo(DiagnosticDescriptor descriptor, Location location, string? messageArg = null, EquatableArray<(string, string)> properties = default)
+ {
+ Descriptor = descriptor;
+ Location = location;
+ MessageArg = messageArg;
+ Properties = properties;
+ }
+
+ public DiagnosticDescriptor Descriptor { get; }
+ public Location Location { get; }
+ public string? MessageArg { get; }
+ public EquatableArray<(string, string)> Properties { get; }
+}
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Diagnostics/DiagnosticHelper.cs b/src/StronglyTypedIds/Diagnostics/DiagnosticHelper.cs
new file mode 100644
index 000000000..71e81a024
--- /dev/null
+++ b/src/StronglyTypedIds/Diagnostics/DiagnosticHelper.cs
@@ -0,0 +1,41 @@
+using System.Collections.Immutable;
+using Microsoft.CodeAnalysis;
+
+namespace StronglyTypedIds.Diagnostics;
+
+internal static class DiagnosticHelper
+{
+ public static void ReportDiagnostic(this SourceProductionContext context, DiagnosticInfo info)
+ {
+ var diagnostic = CreateDiagnostic(info);
+
+ context.ReportDiagnostic(diagnostic);
+ }
+
+ public static Diagnostic CreateDiagnostic(DiagnosticInfo info)
+ {
+ var messageArgs = info.MessageArg is { } arg
+ ? new object[] {arg}
+ : null;
+
+ ImmutableDictionary? properties = null;
+ if (info.Properties is {Count: > 0} props)
+ {
+ var dict = ImmutableDictionary.CreateBuilder();
+ foreach (var prop in props.GetArray()!)
+ {
+ dict.Add(prop.Item1, prop.Item2);
+ }
+
+ properties = dict.ToImmutable()!;
+ }
+
+
+ var diagnostic = Diagnostic.Create(
+ descriptor: info.Descriptor,
+ location: info.Location,
+ messageArgs: messageArgs,
+ properties: properties);
+ return diagnostic;
+ }
+}
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Diagnostics/InvalidBackingTypeDiagnostic.cs b/src/StronglyTypedIds/Diagnostics/InvalidBackingTypeDiagnostic.cs
deleted file mode 100644
index b052e0302..000000000
--- a/src/StronglyTypedIds/Diagnostics/InvalidBackingTypeDiagnostic.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using Microsoft.CodeAnalysis;
-
-namespace StronglyTypedIds.Diagnostics
-{
- internal static class InvalidBackingTypeDiagnostic
- {
- internal const string Id = "STI4";
- internal const string Message = "The StronglyTypedIdBackingType value provided is not a valid combination of flags";
- internal const string Title = "Invalid backing type";
-
- public static Diagnostic Create(SyntaxNode currentNode) =>
- Diagnostic.Create(
- new DiagnosticDescriptor(
- Id, Title, Message, category: Constants.Usage, defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true),
- currentNode.GetLocation());
- }
-}
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Diagnostics/InvalidConverterDiagnostic.cs b/src/StronglyTypedIds/Diagnostics/InvalidConverterDiagnostic.cs
deleted file mode 100644
index bf601c518..000000000
--- a/src/StronglyTypedIds/Diagnostics/InvalidConverterDiagnostic.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using Microsoft.CodeAnalysis;
-
-namespace StronglyTypedIds.Diagnostics
-{
- internal static class InvalidConverterDiagnostic
- {
- internal const string Id = "STI3";
- internal const string Message = "The StronglyTypedIdConverter value provided is not a valid combination of flags";
- internal const string Title = "Invalid converter";
-
- public static Diagnostic Create(SyntaxNode currentNode) =>
- Diagnostic.Create(
- new DiagnosticDescriptor(
- Id, Title, Message, category: Constants.Usage, defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true),
- currentNode.GetLocation());
- }
-}
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Diagnostics/InvalidImplementationsDiagnostic.cs b/src/StronglyTypedIds/Diagnostics/InvalidImplementationsDiagnostic.cs
deleted file mode 100644
index dc4388613..000000000
--- a/src/StronglyTypedIds/Diagnostics/InvalidImplementationsDiagnostic.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using Microsoft.CodeAnalysis;
-
-namespace StronglyTypedIds.Diagnostics
-{
- internal static class InvalidImplementationsDiagnostic
- {
- internal const string Id = "STI5";
- internal const string Message = "The StronglyTypedIdImplementations value provided is not a valid combination of flags";
- internal const string Title = "Invalid implementations value";
-
- public static Diagnostic Create(SyntaxNode currentNode) =>
- Diagnostic.Create(
- new DiagnosticDescriptor(
- Id, Title, Message, category: Constants.Usage, defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true),
- currentNode.GetLocation());
- }
-}
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Diagnostics/InvalidTemplateNameDiagnostic.cs b/src/StronglyTypedIds/Diagnostics/InvalidTemplateNameDiagnostic.cs
new file mode 100644
index 000000000..0cf8f4137
--- /dev/null
+++ b/src/StronglyTypedIds/Diagnostics/InvalidTemplateNameDiagnostic.cs
@@ -0,0 +1,15 @@
+using Microsoft.CodeAnalysis;
+
+namespace StronglyTypedIds.Diagnostics;
+
+internal static class InvalidTemplateNameDiagnostic
+{
+ internal const string Id = "STRONGID001";
+ internal const string Message = "The template name must not be null or whitespace.";
+ internal const string Title = "Invalid template name";
+
+ public static DiagnosticInfo CreateInfo(LocationInfo location)
+ => new(new DiagnosticDescriptor(
+ Id, Title, Message, category: Constants.Usage, defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true),
+ location.ToLocation());
+}
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Diagnostics/MultipleAssemblyAttributeDiagnostic.cs b/src/StronglyTypedIds/Diagnostics/MultipleAssemblyAttributeDiagnostic.cs
new file mode 100644
index 000000000..98ecc2126
--- /dev/null
+++ b/src/StronglyTypedIds/Diagnostics/MultipleAssemblyAttributeDiagnostic.cs
@@ -0,0 +1,15 @@
+using Microsoft.CodeAnalysis;
+
+namespace StronglyTypedIds.Diagnostics;
+
+internal static class MultipleAssemblyAttributeDiagnostic
+{
+ internal const string Id = "STRONGID004";
+ internal const string Message = "You may only have one instance of the StronglyTypedIdDefaults assembly attribute";
+ internal const string Title = "Multiple assembly attributes";
+
+ public static DiagnosticInfo CreateInfo(SyntaxNode currentNode) =>
+ new(new DiagnosticDescriptor(
+ Id, Title, Message, category: Constants.Usage, defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true),
+ currentNode.GetLocation());
+}
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Diagnostics/NotPartialDiagnostic.cs b/src/StronglyTypedIds/Diagnostics/NotPartialDiagnostic.cs
index 6c8435da1..dd50465be 100644
--- a/src/StronglyTypedIds/Diagnostics/NotPartialDiagnostic.cs
+++ b/src/StronglyTypedIds/Diagnostics/NotPartialDiagnostic.cs
@@ -4,7 +4,7 @@ namespace StronglyTypedIds.Diagnostics
{
internal static class NotPartialDiagnostic
{
- internal const string Id = "STI2";
+ internal const string Id = "STRONGID003";
internal const string Message = "The target of the StronglyTypedId attribute must be declared as partial.";
internal const string Title = "Must be partial";
@@ -13,5 +13,10 @@ public static Diagnostic Create(SyntaxNode currentNode) =>
new DiagnosticDescriptor(
Id, Title, Message, category: Constants.Usage, defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true),
currentNode.GetLocation());
+
+ public static DiagnosticInfo CreateInfo(SyntaxNode currentNode)
+ => new(new DiagnosticDescriptor(
+ Id, Title, Message, category: Constants.Usage, defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true),
+ currentNode.GetLocation());
}
}
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Diagnostics/UnknownTemplateCodeFixProvider.cs b/src/StronglyTypedIds/Diagnostics/UnknownTemplateCodeFixProvider.cs
new file mode 100644
index 000000000..282571b30
--- /dev/null
+++ b/src/StronglyTypedIds/Diagnostics/UnknownTemplateCodeFixProvider.cs
@@ -0,0 +1,125 @@
+// Based on https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/1dd5ced072d7d870f6dd698a6c02ad509a122452/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/Settings/UnknownTemplateCodeFixProvider.cs
+
+#nullable disable
+
+using System;
+using System.Collections.Immutable;
+using System.Composition;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+
+namespace StronglyTypedIds.Diagnostics;
+
+[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(UnknownTemplateCodeFixProvider)), Shared]
+internal class UnknownTemplateCodeFixProvider : CodeFixProvider
+{
+ internal const string DefaultHeader =
+ """"
+ // ACTION REQUIRED: This file was automatically added to your project, but it
+ // will not take effect until additional steps are taken to enable it. See
+ // https://github.com/dotnet/roslyn/issues/4655 for more details.
+ //
+ // To enable the template, in Visual Studio 2017, 2019, and 2022:
+ // 1. Select the file in Solution Explorer.
+ // 2. In the 'Properties' window, set the value for 'Build Action'
+ // to one of the following (whichever is available):
+ // - For .NET Core and .NET Standard projects: 'C# analyzer additional file'
+ // - For other projects: 'AdditionalFiles'
+ //
+ // Any instances of PLACEHOLDERID will be replaced with the target ID name
+ // when generating code from this template.
+
+
+ """";
+
+ ///
+ public override ImmutableArray FixableDiagnosticIds { get; } =
+ ImmutableArray.Create(Diagnostics.UnknownTemplateDiagnostic.Id);
+
+ ///
+ public override Task RegisterCodeFixesAsync(CodeFixContext context)
+ {
+ var project = context.Document.Project;
+ var workspace = project.Solution.Workspace;
+
+ // if we can't add extra documents, there's nothing we can do
+ if (!workspace.CanApplyChange(ApplyChangesKind.AddAdditionalDocument))
+ {
+ return Task.CompletedTask;
+ }
+
+ foreach (var diagnostic in context.Diagnostics)
+ {
+ if(!diagnostic.Properties.TryGetValue(UnknownTemplateDiagnostic.TemplateName, out var templateName))
+ {
+ // This shouldn't happen, but play it safe
+ continue;
+ }
+
+ // check if the template file already exists
+ var alreadyAdded = false;
+ foreach (var document in project.AdditionalDocuments)
+ {
+ if (document.Name.Equals(templateName, StringComparison.OrdinalIgnoreCase))
+ {
+ alreadyAdded = true;
+ break;
+ }
+ }
+
+ if (alreadyAdded)
+ {
+ continue;
+ }
+
+ context.RegisterCodeFix(
+ CodeAction.Create(
+ $"Add '{templateName}.typedid' template to the project",
+ cancellationToken => GetTransformedSolutionAsync(context.Document, templateName, cancellationToken),
+ nameof(UnknownTemplateCodeFixProvider)),
+ diagnostic);
+ }
+
+ return Task.CompletedTask;
+ }
+
+ ///
+ public override FixAllProvider GetFixAllProvider()
+ {
+ // This code fix does not support fix all actions.
+ return null;
+ }
+
+ private static Task GetTransformedSolutionAsync(Document document, string templateName, CancellationToken cancellationToken)
+ {
+ // Currently unused
+ _ = cancellationToken;
+
+ var project = document.Project;
+ var solution = project.Solution;
+
+ var newDocumentId = DocumentId.CreateNewId(project.Id);
+
+ var templateContent = GetTemplateContent(templateName);
+
+ var newSolution = solution.AddAdditionalDocument(newDocumentId, $"{templateName}.typedid", templateContent);
+
+ return Task.FromResult(newSolution);
+ }
+
+ internal static string GetTemplateContent(string templateName)
+ {
+ var templateContent = templateName switch
+ {
+ { } x when x.Contains("int", StringComparison.OrdinalIgnoreCase) => EmbeddedSources.LoadEmbeddedTypedId("int-full.typedid"),
+ { } x when x.Contains("long", StringComparison.OrdinalIgnoreCase) => EmbeddedSources.LoadEmbeddedTypedId("long-full.typedid"),
+ { } x when x.Contains("string", StringComparison.OrdinalIgnoreCase) => EmbeddedSources.LoadEmbeddedTypedId("string-full.typedid"),
+ _ => EmbeddedSources.LoadEmbeddedTypedId("guid-full.typedid"),
+ };
+
+ return DefaultHeader + templateContent;
+ }
+}
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Diagnostics/UnknownTemplateDiagnostic.cs b/src/StronglyTypedIds/Diagnostics/UnknownTemplateDiagnostic.cs
new file mode 100644
index 000000000..7347efd9d
--- /dev/null
+++ b/src/StronglyTypedIds/Diagnostics/UnknownTemplateDiagnostic.cs
@@ -0,0 +1,21 @@
+using Microsoft.CodeAnalysis;
+
+namespace StronglyTypedIds.Diagnostics;
+
+internal static class UnknownTemplateDiagnostic
+{
+ internal const string Id = "STRONGID002";
+ internal const string Title = "Unknown .typedid template";
+ internal const string TemplateName = nameof(TemplateName);
+
+ public static DiagnosticInfo CreateInfo(LocationInfo location, string name)
+ => new(CreateDescriptor(),
+ location.ToLocation(),
+ name,
+ new EquatableArray<(string, string)>(new[] {(TemplateName, name)}));
+
+ public static DiagnosticDescriptor CreateDescriptor()
+ => new(
+ Id, Title, "Could not find '{0}.typedid' template. Ensure the template exists in the project and has a build action of 'Additional Files'.",
+ category: Constants.Usage, defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true);
+}
\ No newline at end of file
diff --git a/src/StronglyTypedIds/EmbeddedSources.Guid.cs b/src/StronglyTypedIds/EmbeddedSources.Guid.cs
new file mode 100644
index 000000000..63ca8556a
--- /dev/null
+++ b/src/StronglyTypedIds/EmbeddedSources.Guid.cs
@@ -0,0 +1,210 @@
+namespace StronglyTypedIds;
+
+internal static partial class EmbeddedSources
+{
+ private const string GuidTemplate = """
+ partial struct PLACEHOLDERID :
+ #if NET6_0_OR_GREATER
+ global::System.ISpanFormattable,
+ #endif
+ #if NET7_0_OR_GREATER
+ global::System.IParsable, global::System.ISpanParsable,
+ #endif
+ global::System.IComparable, global::System.IEquatable, global::System.IFormattable
+ {
+ public global::System.Guid Value { get; }
+
+ public PLACEHOLDERID(global::System.Guid value)
+ {
+ Value = value;
+ }
+
+ public static PLACEHOLDERID New() => new PLACEHOLDERID(global::System.Guid.NewGuid());
+ public static readonly PLACEHOLDERID Empty = new PLACEHOLDERID(global::System.Guid.Empty);
+
+ ///
+ public bool Equals(PLACEHOLDERID other) => this.Value.Equals(other.Value);
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ return obj is PLACEHOLDERID other && Equals(other);
+ }
+
+ public override int GetHashCode() => Value.GetHashCode();
+
+ public override string ToString() => Value.ToString();
+
+ public static bool operator ==(PLACEHOLDERID a, PLACEHOLDERID b) => a.Equals(b);
+ public static bool operator !=(PLACEHOLDERID a, PLACEHOLDERID b) => !(a == b);
+ public static bool operator > (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) > 0;
+ public static bool operator < (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) < 0;
+ public static bool operator >= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) >= 0;
+ public static bool operator <= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) <= 0;
+
+ ///
+ public int CompareTo(PLACEHOLDERID other) => Value.CompareTo(other.Value);
+
+ public partial class PLACEHOLDERIDTypeConverter : global::System.ComponentModel.TypeConverter
+ {
+ public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType)
+ {
+ return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
+ }
+
+ public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value)
+ {
+ return value switch
+ {
+ global::System.Guid guidValue => new PLACEHOLDERID(guidValue),
+ string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new PLACEHOLDERID(result),
+ _ => base.ConvertFrom(context, culture, value),
+ };
+ }
+
+ public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType)
+ {
+ return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType);
+ }
+
+ public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType)
+ {
+ if (value is PLACEHOLDERID idValue)
+ {
+ if (destinationType == typeof(global::System.Guid))
+ {
+ return idValue.Value;
+ }
+
+ if (destinationType == typeof(string))
+ {
+ return idValue.Value.ToString();
+ }
+ }
+
+ return base.ConvertTo(context, culture, value, destinationType);
+ }
+ }
+
+ public partial class PLACEHOLDERIDSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter
+ {
+ public override bool CanConvert(global::System.Type typeToConvert)
+ => typeToConvert == typeof(global::System.Guid) || typeToConvert == typeof(string) || base.CanConvert(typeToConvert);
+
+ public override PLACEHOLDERID Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
+ => new (reader.GetGuid());
+
+ public override void Write(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options)
+ => writer.WriteStringValue(value.Value);
+
+ #if NET6_0_OR_GREATER
+ public override PLACEHOLDERID ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
+ => new(global::System.Guid.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the PLACEHOLDERID property was null")));
+
+ public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options)
+ => writer.WritePropertyName(value.Value.ToString());
+ #endif
+ }
+
+ public static PLACEHOLDERID Parse(string input)
+ => new(global::System.Guid.Parse(input));
+
+ #if NET7_0_OR_GREATER
+ ///
+ public static PLACEHOLDERID Parse(string input, global::System.IFormatProvider? provider)
+ => new(global::System.Guid.Parse(input, provider));
+
+ ///
+ public static bool TryParse(
+ [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input,
+ global::System.IFormatProvider? provider,
+ out PLACEHOLDERID result)
+ {
+ if (input is null)
+ {
+ result = default;
+ return false;
+ }
+
+ if (global::System.Guid.TryParse(input, provider, out var guid))
+ {
+ result = new(guid);
+ return true;
+ }
+ else
+ {
+ result = default;
+ return false;
+ }
+ }
+ #endif
+
+ ///
+ public string ToString(
+ #if NET7_0_OR_GREATER
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)]
+ #endif
+ string? format,
+ global::System.IFormatProvider? formatProvider)
+ => Value.ToString(format, formatProvider);
+
+ #if NETCOREAPP2_1_OR_GREATER
+ public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input)
+ => new(global::System.Guid.Parse(input));
+ #endif
+
+ #if NET6_0_OR_GREATER
+ #if NET7_0_OR_GREATER
+ ///
+ #endif
+ public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider)
+ #if NET7_0_OR_GREATER
+ => new(global::System.Guid.Parse(input, provider));
+ #else
+ => new(global::System.Guid.Parse(input));
+ #endif
+
+ #if NET7_0_OR_GREATER
+ ///
+ #endif
+ public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out PLACEHOLDERID result)
+ {
+ #if NET7_0_OR_GREATER
+ if (global::System.Guid.TryParse(input, provider, out var guid))
+ #else
+ if (global::System.Guid.TryParse(input, out var guid))
+ #endif
+ {
+ result = new(guid);
+ return true;
+ }
+ else
+ {
+ result = default;
+ return false;
+ }
+ }
+
+ ///
+ public bool TryFormat(
+ global::System.Span destination,
+ out int charsWritten,
+ #if NET7_0_OR_GREATER
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)]
+ #endif
+ global::System.ReadOnlySpan format,
+ global::System.IFormatProvider? provider)
+ => Value.TryFormat(destination, out charsWritten, format);
+
+ ///
+ public bool TryFormat(
+ global::System.Span destination,
+ out int charsWritten,
+ #if NET7_0_OR_GREATER
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)]
+ #endif
+ global::System.ReadOnlySpan format = default)
+ => Value.TryFormat(destination, out charsWritten, format);
+ #endif
+ }
+ """;
+}
\ No newline at end of file
diff --git a/src/StronglyTypedIds/EmbeddedSources.Int.cs b/src/StronglyTypedIds/EmbeddedSources.Int.cs
new file mode 100644
index 000000000..2690ad76b
--- /dev/null
+++ b/src/StronglyTypedIds/EmbeddedSources.Int.cs
@@ -0,0 +1,205 @@
+namespace StronglyTypedIds;
+
+internal static partial class EmbeddedSources
+{
+ private const string IntTemplate = """
+ partial struct PLACEHOLDERID :
+ #if NET6_0_OR_GREATER
+ global::System.ISpanFormattable,
+ #endif
+ #if NET7_0_OR_GREATER
+ global::System.IParsable, global::System.ISpanParsable,
+ #endif
+ global::System.IComparable, global::System.IEquatable, global::System.IFormattable
+ {
+ public int Value { get; }
+
+ public PLACEHOLDERID(int value)
+ {
+ Value = value;
+ }
+
+ public static readonly PLACEHOLDERID Empty = new PLACEHOLDERID(0);
+
+ ///
+ public bool Equals(PLACEHOLDERID other) => this.Value.Equals(other.Value);
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ return obj is PLACEHOLDERID other && Equals(other);
+ }
+
+ public override int GetHashCode() => Value.GetHashCode();
+
+ public override string ToString() => Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture);
+
+ public static bool operator ==(PLACEHOLDERID a, PLACEHOLDERID b) => a.Equals(b);
+ public static bool operator !=(PLACEHOLDERID a, PLACEHOLDERID b) => !(a == b);
+ public static bool operator > (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) > 0;
+ public static bool operator < (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) < 0;
+ public static bool operator >= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) >= 0;
+ public static bool operator <= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) <= 0;
+
+ ///
+ public int CompareTo(PLACEHOLDERID other) => Value.CompareTo(other.Value);
+
+ public partial class PLACEHOLDERIDTypeConverter : global::System.ComponentModel.TypeConverter
+ {
+ public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType)
+ {
+ return sourceType == typeof(int) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
+ }
+
+ public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value)
+ {
+ return value switch
+ {
+ int intValue => new PLACEHOLDERID(intValue),
+ string stringValue when !string.IsNullOrEmpty(stringValue) && int.TryParse(stringValue, out var result) => new PLACEHOLDERID(result),
+ _ => base.ConvertFrom(context, culture, value),
+ };
+ }
+
+ public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType)
+ {
+ return sourceType == typeof(int) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType);
+ }
+
+ public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType)
+ {
+ if (value is PLACEHOLDERID idValue)
+ {
+ if (destinationType == typeof(int))
+ {
+ return idValue.Value;
+ }
+
+ if (destinationType == typeof(string))
+ {
+ return idValue.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture);
+ }
+ }
+
+ return base.ConvertTo(context, culture, value, destinationType);
+ }
+ }
+
+ public partial class PLACEHOLDERIDSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter
+ {
+ public override bool CanConvert(global::System.Type typeToConvert)
+ => typeToConvert == typeof(int) || typeToConvert == typeof(string) || base.CanConvert(typeToConvert);
+
+ public override PLACEHOLDERID Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
+ => new (reader.GetInt32());
+
+ public override void Write(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options)
+ => writer.WriteNumberValue(value.Value);
+
+ #if NET6_0_OR_GREATER
+ public override PLACEHOLDERID ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
+ => new(int.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the PLACEHOLDERID property was null")));
+
+ public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options)
+ => writer.WritePropertyName(value.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture));
+ #endif
+ }
+
+ public static PLACEHOLDERID Parse(string input)
+ => new(int.Parse(input));
+
+ #if NET7_0_OR_GREATER
+ ///
+ public static PLACEHOLDERID Parse(string input, global::System.IFormatProvider? provider)
+ => new(int.Parse(input, provider));
+
+ ///
+ public static bool TryParse(
+ [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input,
+ global::System.IFormatProvider? provider,
+ out PLACEHOLDERID result)
+ {
+ if (input is null)
+ {
+ result = default;
+ return false;
+ }
+
+ if (int.TryParse(input, provider, out var value))
+ {
+ result = new(value);
+ return true;
+ }
+
+ result = default;
+ return false;
+ }
+ #endif
+
+ ///
+ public string ToString(
+ #if NET7_0_OR_GREATER
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.NumericFormat)]
+ #endif
+ string? format,
+ global::System.IFormatProvider? formatProvider)
+ => Value.ToString(format, formatProvider);
+
+ #if NETCOREAPP2_1_OR_GREATER
+ public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input)
+ => new(int.Parse(input));
+ #endif
+
+ #if NET6_0_OR_GREATER
+ #if NET7_0_OR_GREATER
+ ///
+ #endif
+ public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider)
+ #if NET7_0_OR_GREATER
+ => new(int.Parse(input, provider));
+ #else
+ => new(int.Parse(input));
+ #endif
+
+ #if NET7_0_OR_GREATER
+ ///
+ #endif
+ public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out PLACEHOLDERID result)
+ {
+ #if NET7_0_OR_GREATER
+ if (int.TryParse(input, provider, out var value))
+ #else
+ if (int.TryParse(input, out var value))
+ #endif
+ {
+ result = new(value);
+ return true;
+ }
+
+ result = default;
+ return false;
+ }
+
+ ///
+ public bool TryFormat(
+ global::System.Span destination,
+ out int charsWritten,
+ #if NET7_0_OR_GREATER
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)]
+ #endif
+ global::System.ReadOnlySpan format,
+ global::System.IFormatProvider? provider)
+ => Value.TryFormat(destination, out charsWritten, format);
+
+ ///
+ public bool TryFormat(
+ global::System.Span destination,
+ out int charsWritten,
+ #if NET7_0_OR_GREATER
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)]
+ #endif
+ global::System.ReadOnlySpan format = default)
+ => Value.TryFormat(destination, out charsWritten, format);
+ #endif
+ }
+ """;
+}
\ No newline at end of file
diff --git a/src/StronglyTypedIds/EmbeddedSources.Long.cs b/src/StronglyTypedIds/EmbeddedSources.Long.cs
new file mode 100644
index 000000000..c3a3bd3f2
--- /dev/null
+++ b/src/StronglyTypedIds/EmbeddedSources.Long.cs
@@ -0,0 +1,205 @@
+namespace StronglyTypedIds;
+
+internal static partial class EmbeddedSources
+{
+ private const string LongTemplate = """
+ partial struct PLACEHOLDERID :
+ #if NET6_0_OR_GREATER
+ global::System.ISpanFormattable,
+ #endif
+ #if NET7_0_OR_GREATER
+ global::System.IParsable, global::System.ISpanParsable,
+ #endif
+ global::System.IComparable, global::System.IEquatable, global::System.IFormattable
+ {
+ public long Value { get; }
+
+ public PLACEHOLDERID(long value)
+ {
+ Value = value;
+ }
+
+ public static readonly PLACEHOLDERID Empty = new PLACEHOLDERID(0);
+
+ ///
+ public bool Equals(PLACEHOLDERID other) => this.Value.Equals(other.Value);
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ return obj is PLACEHOLDERID other && Equals(other);
+ }
+
+ public override int GetHashCode() => Value.GetHashCode();
+
+ public override string ToString() => Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture);
+
+ public static bool operator ==(PLACEHOLDERID a, PLACEHOLDERID b) => a.Equals(b);
+ public static bool operator !=(PLACEHOLDERID a, PLACEHOLDERID b) => !(a == b);
+ public static bool operator > (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) > 0;
+ public static bool operator < (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) < 0;
+ public static bool operator >= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) >= 0;
+ public static bool operator <= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) <= 0;
+
+ ///
+ public int CompareTo(PLACEHOLDERID other) => Value.CompareTo(other.Value);
+
+ public partial class PLACEHOLDERIDTypeConverter : global::System.ComponentModel.TypeConverter
+ {
+ public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType)
+ {
+ return sourceType == typeof(long) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
+ }
+
+ public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value)
+ {
+ return value switch
+ {
+ long longValue => new PLACEHOLDERID(longValue),
+ string stringValue when !string.IsNullOrEmpty(stringValue) && long.TryParse(stringValue, out var result) => new PLACEHOLDERID(result),
+ _ => base.ConvertFrom(context, culture, value),
+ };
+ }
+
+ public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType)
+ {
+ return sourceType == typeof(long) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType);
+ }
+
+ public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType)
+ {
+ if (value is PLACEHOLDERID idValue)
+ {
+ if (destinationType == typeof(long))
+ {
+ return idValue.Value;
+ }
+
+ if (destinationType == typeof(string))
+ {
+ return idValue.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture);
+ }
+ }
+
+ return base.ConvertTo(context, culture, value, destinationType);
+ }
+ }
+
+ public partial class PLACEHOLDERIDSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter
+ {
+ public override bool CanConvert(global::System.Type typeToConvert)
+ => typeToConvert == typeof(long) || typeToConvert == typeof(string) || base.CanConvert(typeToConvert);
+
+ public override PLACEHOLDERID Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
+ => new (reader.GetInt64());
+
+ public override void Write(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options)
+ => writer.WriteNumberValue(value.Value);
+
+ #if NET6_0_OR_GREATER
+ public override PLACEHOLDERID ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
+ => new(long.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the PLACEHOLDERID property was null")));
+
+ public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options)
+ => writer.WritePropertyName(value.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture));
+ #endif
+ }
+
+ public static PLACEHOLDERID Parse(string input)
+ => new(long.Parse(input));
+
+ #if NET7_0_OR_GREATER
+ ///
+ public static PLACEHOLDERID Parse(string input, global::System.IFormatProvider? provider)
+ => new(long.Parse(input, provider));
+
+ ///
+ public static bool TryParse(
+ [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input,
+ global::System.IFormatProvider? provider,
+ out PLACEHOLDERID result)
+ {
+ if (input is null)
+ {
+ result = default;
+ return false;
+ }
+
+ if (long.TryParse(input, provider, out var value))
+ {
+ result = new(value);
+ return true;
+ }
+
+ result = default;
+ return false;
+ }
+ #endif
+
+ ///
+ public string ToString(
+ #if NET7_0_OR_GREATER
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.NumericFormat)]
+ #endif
+ string? format,
+ global::System.IFormatProvider? formatProvider)
+ => Value.ToString(format, formatProvider);
+
+ #if NETCOREAPP2_1_OR_GREATER
+ public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input)
+ => new(long.Parse(input));
+ #endif
+
+ #if NET6_0_OR_GREATER
+ #if NET7_0_OR_GREATER
+ ///
+ #endif
+ public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider)
+ #if NET7_0_OR_GREATER
+ => new(long.Parse(input, provider));
+ #else
+ => new(long.Parse(input));
+ #endif
+
+ #if NET7_0_OR_GREATER
+ ///
+ #endif
+ public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out PLACEHOLDERID result)
+ {
+ #if NET7_0_OR_GREATER
+ if (long.TryParse(input, provider, out var value))
+ #else
+ if (long.TryParse(input, out var value))
+ #endif
+ {
+ result = new(value);
+ return true;
+ }
+
+ result = default;
+ return false;
+ }
+
+ ///
+ public bool TryFormat(
+ global::System.Span destination,
+ out int charsWritten,
+ #if NET7_0_OR_GREATER
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)]
+ #endif
+ global::System.ReadOnlySpan format,
+ global::System.IFormatProvider? provider)
+ => Value.TryFormat(destination, out charsWritten, format);
+
+ ///
+ public bool TryFormat(
+ global::System.Span destination,
+ out int charsWritten,
+ #if NET7_0_OR_GREATER
+ [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)]
+ #endif
+ global::System.ReadOnlySpan format = default)
+ => Value.TryFormat(destination, out charsWritten, format);
+ #endif
+ }
+ """;
+}
\ No newline at end of file
diff --git a/src/StronglyTypedIds/EmbeddedSources.String.cs b/src/StronglyTypedIds/EmbeddedSources.String.cs
new file mode 100644
index 000000000..30d260a4e
--- /dev/null
+++ b/src/StronglyTypedIds/EmbeddedSources.String.cs
@@ -0,0 +1,194 @@
+namespace StronglyTypedIds;
+
+internal static partial class EmbeddedSources
+{
+ private const string StringTemplate = """
+ partial struct PLACEHOLDERID :
+ #if NET6_0_OR_GREATER
+ global::System.ISpanFormattable,
+ #endif
+ #if NET7_0_OR_GREATER
+ global::System.IParsable, global::System.ISpanParsable,
+ #endif
+ global::System.IComparable, global::System.IEquatable, global::System.IFormattable
+ {
+ public string Value { get; }
+
+ public PLACEHOLDERID(string value)
+ {
+ Value = value ?? throw new global::System.ArgumentNullException(nameof(value));
+ }
+
+ public static readonly PLACEHOLDERID Empty = new PLACEHOLDERID(string.Empty);
+
+ ///
+ public bool Equals(PLACEHOLDERID other)
+ => (Value, other.Value) switch
+ {
+ (null, null) => true,
+ (null, _) => false,
+ (_, null) => false,
+ (_, _) => Value.Equals(other.Value, global::System.StringComparison.Ordinal),
+ };
+
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ return obj is PLACEHOLDERID other && Equals(other);
+ }
+
+ public override int GetHashCode() => Value.GetHashCode();
+
+ public override string ToString() => Value;
+
+ public static bool operator ==(PLACEHOLDERID a, PLACEHOLDERID b) => a.Equals(b);
+ public static bool operator !=(PLACEHOLDERID a, PLACEHOLDERID b) => !(a == b);
+ public static bool operator > (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) > 0;
+ public static bool operator < (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) < 0;
+ public static bool operator >= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) >= 0;
+ public static bool operator <= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) <= 0;
+
+ ///
+ public int CompareTo(PLACEHOLDERID other)
+ => (Value, other.Value) switch
+ {
+ (null, null) => 0,
+ (null, _) => -1,
+ (_, null) => 1,
+ (_, _) => string.CompareOrdinal(Value, other.Value),
+ };
+
+ public partial class PLACEHOLDERIDTypeConverter : global::System.ComponentModel.TypeConverter
+ {
+ public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType)
+ {
+ return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
+ }
+
+ public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value)
+ {
+ if (value is string stringValue)
+ {
+ return new PLACEHOLDERID(stringValue);
+ }
+
+ return base.ConvertFrom(context, culture, value);
+ }
+
+ public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType)
+ {
+ return sourceType == typeof(string) || base.CanConvertTo(context, sourceType);
+ }
+
+ public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType)
+ {
+ if (value is PLACEHOLDERID idValue)
+ {
+ if (destinationType == typeof(string))
+ {
+ return idValue.Value;
+ }
+ }
+
+ return base.ConvertTo(context, culture, value, destinationType);
+ }
+ }
+
+ public partial class PLACEHOLDERIDSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter
+ {
+ public override bool CanConvert(global::System.Type typeToConvert)
+ => typeToConvert == typeof(string) || base.CanConvert(typeToConvert);
+
+ public override PLACEHOLDERID Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
+ => new (reader.GetString()!);
+
+ public override void Write(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options)
+ => writer.WriteStringValue(value.Value);
+
+ #if NET6_0_OR_GREATER
+ public override PLACEHOLDERID ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
+ => new(reader.GetString() ?? throw new global::System.FormatException("The string for the PLACEHOLDERID property was null"));
+
+ public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options)
+ => writer.WritePropertyName(value.Value);
+ #endif
+ }
+
+ public static PLACEHOLDERID Parse(string input)
+ => new(input);
+
+ #if NET7_0_OR_GREATER
+ ///
+ public static PLACEHOLDERID Parse(string input, global::System.IFormatProvider? provider)
+ => new(input);
+
+ ///
+ public static bool TryParse(
+ [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input,
+ global::System.IFormatProvider? provider,
+ out PLACEHOLDERID result)
+ {
+ if (input is null)
+ {
+ result = default;
+ return false;
+ }
+
+ result = new(input);
+ return true;
+ }
+ #endif
+
+ ///
+ public string ToString(string? format, global::System.IFormatProvider? formatProvider)
+ => Value;
+
+ #if NETCOREAPP2_1_OR_GREATER
+ public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input)
+ => new(input.ToString());
+ #endif
+
+ #if NET6_0_OR_GREATER
+ #if NET7_0_OR_GREATER
+ ///
+ #endif
+ public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider)
+ => new(input.ToString());
+
+ #if NET7_0_OR_GREATER
+ ///
+ #endif
+ public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out PLACEHOLDERID result)
+ {
+ result = new(input.ToString());
+ return true;
+ }
+
+ ///
+ public bool TryFormat(
+ global::System.Span destination,
+ out int charsWritten,
+ global::System.ReadOnlySpan format,
+ global::System.IFormatProvider? provider)
+ => TryFormat(destination, out charsWritten, format);
+
+ ///
+ public bool TryFormat(
+ global::System.Span destination,
+ out int charsWritten,
+ global::System.ReadOnlySpan format = default)
+ {
+ if (destination.Length > Value.Length)
+ {
+ global::System.MemoryExtensions.AsSpan(Value).CopyTo(destination);
+ charsWritten = Value.Length;
+ return true;
+ }
+
+ charsWritten = default;
+ return false;
+ }
+ #endif
+ }
+ """;
+}
\ No newline at end of file
diff --git a/src/StronglyTypedIds/EmbeddedSources.cs b/src/StronglyTypedIds/EmbeddedSources.cs
index e1f229779..e54f812ab 100644
--- a/src/StronglyTypedIds/EmbeddedSources.cs
+++ b/src/StronglyTypedIds/EmbeddedSources.cs
@@ -3,154 +3,60 @@
using System.Reflection;
using System.Text;
-namespace StronglyTypedIds
-{
- internal static class EmbeddedSources
- {
- private static readonly Assembly ThisAssembly = typeof(EmbeddedSources).Assembly;
- internal static readonly string StronglyTypedIdAttributeSource = LoadTemplateForEmitting("StronglyTypedIdAttribute");
- internal static readonly string StronglyTypedIdDefaultsAttributeSource = LoadTemplateForEmitting("StronglyTypedIdDefaultsAttribute");
- internal static readonly string StronglyTypedIdBackingTypeSource = LoadTemplateForEmitting("StronglyTypedIdBackingType");
- internal static readonly string StronglyTypedIdConverterSource = LoadTemplateForEmitting("StronglyTypedIdConverter");
- internal static readonly string StronglyTypedIdImplementationsSource = LoadTemplateForEmitting("StronglyTypedIdImplementations");
-
- private static readonly string AutoGeneratedHeader = LoadEmbeddedResource("StronglyTypedIds.Templates.AutoGeneratedHeader.cs");
-
- internal static readonly ResourceCollection GuidResources = new(
- AutoGeneratedHeader,
- LoadEmbeddedResource("StronglyTypedIds.Templates.Guid.Guid_Base.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.Guid.Guid_NewtonsoftJsonConverter.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.Guid.Guid_SystemTextJsonConverter.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.Guid.Guid_TypeConverter.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.Guid.Guid_EfCoreValueConverter.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.Guid.Guid_DapperTypeHandler.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.Guid.Guid_IComparable.cs"),
- false
- );
-
- internal static readonly ResourceCollection IntResources = new(
- AutoGeneratedHeader,
- LoadEmbeddedResource("StronglyTypedIds.Templates.Int.Int_Base.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.Int.Int_NewtonsoftJsonConverter.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.Int.Int_SystemTextJsonConverter.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.Int.Int_TypeConverter.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.Int.Int_EfCoreValueConverter.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.Int.Int_DapperTypeHandler.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.Int.Int_IComparable.cs"),
- false
- );
+namespace StronglyTypedIds;
- internal static readonly ResourceCollection LongResources = new(
- AutoGeneratedHeader,
- LoadEmbeddedResource("StronglyTypedIds.Templates.Long.Long_Base.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.Long.Long_NewtonsoftJsonConverter.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.Long.Long_SystemTextJsonConverter.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.Long.Long_TypeConverter.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.Long.Long_EfCoreValueConverter.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.Long.Long_DapperTypeHandler.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.Long.Long_IComparable.cs"),
- false
- );
-
- internal static readonly ResourceCollection StringResources = new(
- AutoGeneratedHeader,
- LoadEmbeddedResource("StronglyTypedIds.Templates.String.String_Base.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.String.String_NewtonsoftJsonConverter.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.String.String_SystemTextJsonConverter.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.String.String_TypeConverter.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.String.String_EfCoreValueConverter.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.String.String_DapperTypeHandler.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.String.String_IComparable.cs"),
- false
- );
-
- internal static readonly ResourceCollection NullableStringResources = new(
- AutoGeneratedHeader,
- LoadEmbeddedResource("StronglyTypedIds.Templates.NullableString.NullableString_Base.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.NullableString.NullableString_NewtonsoftJsonConverter.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.NullableString.NullableString_SystemTextJsonConverter.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.NullableString.NullableString_TypeConverter.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.NullableString.NullableString_EfCoreValueConverter.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.NullableString.NullableString_DapperTypeHandler.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.NullableString.NullableString_IComparable.cs"),
- true
- );
-
- internal static readonly ResourceCollection NewIdResources = new(
- AutoGeneratedHeader,
- LoadEmbeddedResource("StronglyTypedIds.Templates.NewId.NewId_Base.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.NewId.NewId_NewtonsoftJsonConverter.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.NewId.NewId_SystemTextJsonConverter.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.NewId.NewId_TypeConverter.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.NewId.NewId_EfCoreValueConverter.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.NewId.NewId_DapperTypeHandler.cs"),
- LoadEmbeddedResource("StronglyTypedIds.Templates.NewId.NewId_IComparable.cs"),
- false
- );
+internal static partial class EmbeddedSources
+{
+ private static readonly Assembly ThisAssembly = typeof(EmbeddedSources).Assembly;
+ internal static readonly string StronglyTypedIdAttributeSource = LoadAttributeTemplateForEmitting("StronglyTypedIdAttribute");
+ internal static readonly string StronglyTypedIdDefaultsAttributeSource = LoadAttributeTemplateForEmitting("StronglyTypedIdDefaultsAttribute");
+ internal static readonly string TemplateSource = LoadAttributeTemplateForEmitting("Template");
- internal const string TypeConverterAttributeSource = " [System.ComponentModel.TypeConverter(typeof(TESTIDTypeConverter))]";
- internal const string NewtonsoftJsonAttributeSource = " [Newtonsoft.Json.JsonConverter(typeof(TESTIDNewtonsoftJsonConverter))]";
- internal const string SystemTextJsonAttributeSource = " [System.Text.Json.Serialization.JsonConverter(typeof(TESTIDSystemTextJsonConverter))]";
+ internal static readonly string AutoGeneratedHeader = LoadEmbeddedResource("StronglyTypedIds.Templates.AutoGeneratedHeader.cs");
- internal static string LoadEmbeddedResource(string resourceName)
+ internal static string GetTemplate(Template template)
+ => template switch
{
- var resourceStream = ThisAssembly.GetManifestResourceStream(resourceName);
- if (resourceStream is null)
- {
- var existingResources = ThisAssembly.GetManifestResourceNames();
- throw new ArgumentException($"Could not find embedded resource {resourceName}. Available names: {string.Join(", ", existingResources)}");
- }
+ Template.Guid => GuidTemplate,
+ Template.Int => IntTemplate,
+ Template.Long => LongTemplate,
+ Template.String => StringTemplate,
+ _ => string.Empty,
+ };
- using var reader = new StreamReader(resourceStream, Encoding.UTF8);
+ internal static string LoadEmbeddedTypedId(string templateName)
+ => LoadEmbeddedResource($"StronglyTypedIds.Templates.{templateName}");
- return reader.ReadToEnd();
- }
-
- public readonly struct ResourceCollection
+ internal static string LoadEmbeddedResource(string resourceName)
+ {
+ var resourceStream = ThisAssembly.GetManifestResourceStream(resourceName);
+ if (resourceStream is null)
{
- public string Header { get; }
- public bool NullableEnable { get; }
- public string BaseId { get; }
- public string Newtonsoft { get; }
- public string SystemTextJson { get; }
- public string TypeConverter { get; }
- public string EfCoreValueConverter { get; }
- public string DapperTypeHandler { get; }
- public string Comparable { get; }
-
- public ResourceCollection(
- string header,
- string baseId,
- string newtonsoft,
- string systemTextJson,
- string typeConverter,
- string efCoreValueConverter,
- string dapperTypeHandler,
- string comparable,
- bool nullableEnable)
- {
- BaseId = baseId;
- Newtonsoft = newtonsoft;
- SystemTextJson = systemTextJson;
- TypeConverter = typeConverter;
- EfCoreValueConverter = efCoreValueConverter;
- DapperTypeHandler = dapperTypeHandler;
- Comparable = comparable;
- NullableEnable = nullableEnable;
- Header = header;
- }
+ var existingResources = ThisAssembly.GetManifestResourceNames();
+ throw new ArgumentException($"Could not find embedded resource {resourceName}. Available names: {string.Join(", ", existingResources)}");
}
- internal static string LoadTemplateForEmitting(string resourceName)
- {
- var resource = LoadEmbeddedResource($"StronglyTypedIds.Templates.Sources.{resourceName}.cs");
- return AutoGeneratedHeader + @"#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES
+ using var reader = new StreamReader(resourceStream, Encoding.UTF8);
-" + resource
- .Replace("public sealed", "internal sealed")
- .Replace("public enum", "internal enum")
- + @"
-#endif";
- }
+ return reader.ReadToEnd();
+ }
+
+ internal static string LoadAttributeTemplateForEmitting(string resourceName)
+ {
+ var resource = LoadEmbeddedResource($"StronglyTypedIds.Templates.Sources.{resourceName}.cs");
+ // AutoGeneratedHeader is included directly in the file
+ // so that it's there if you're directly referencing the attributes package too
+ return resource
+ .Replace("#nullable enable", """
+ #nullable enable
+
+ #if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES
+ """)
+ .Replace("public sealed", "internal sealed")
+ .Replace("public enum", "internal enum")
+ + """
+
+ #endif
+ """;
}
}
\ No newline at end of file
diff --git a/src/StronglyTypedIds/EquatableArray.cs b/src/StronglyTypedIds/EquatableArray.cs
new file mode 100644
index 000000000..70c1030e0
--- /dev/null
+++ b/src/StronglyTypedIds/EquatableArray.cs
@@ -0,0 +1,110 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+
+namespace StronglyTypedIds;
+
+///
+/// An immutable, equatable array. This is equivalent to but with value equality support.
+///
+/// The type of values in the array.
+internal readonly struct EquatableArray : IEquatable>, IEnumerable
+ where T : IEquatable
+{
+ public static readonly EquatableArray Empty = new(Array.Empty());
+
+ ///
+ /// The underlying array.
+ ///
+ private readonly T[]? _array;
+
+ ///
+ /// Creates a new instance.
+ ///
+ /// The input to wrap.
+ public EquatableArray(T[] array)
+ {
+ _array = array;
+ }
+
+ ///
+ public bool Equals(EquatableArray array)
+ {
+ return AsSpan().SequenceEqual(array.AsSpan());
+ }
+
+ ///
+ public override bool Equals(object? obj)
+ {
+ return obj is EquatableArray array && Equals(this, array);
+ }
+
+ ///
+ public override int GetHashCode()
+ {
+ if (_array is not T[] array)
+ {
+ return 0;
+ }
+
+ HashCode hashCode = default;
+
+ foreach (T item in array)
+ {
+ hashCode.Add(item);
+ }
+
+ return hashCode.ToHashCode();
+ }
+
+ ///
+ /// Returns a wrapping the current items.
+ ///
+ /// A wrapping the current items.
+ public ReadOnlySpan AsSpan()
+ {
+ return _array.AsSpan();
+ }
+
+ ///
+ /// Gets the underlying array if there is one
+ ///
+ public T[]? GetArray() => _array;
+
+ ///
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return ((IEnumerable)(_array ?? Array.Empty())).GetEnumerator();
+ }
+
+ ///
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return ((IEnumerable)(_array ?? Array.Empty())).GetEnumerator();
+ }
+
+ public int Count => _array?.Length ?? 0;
+
+ ///
+ /// Checks whether two values are the same.
+ ///
+ /// The first value.
+ /// The second value.
+ /// Whether and are equal.
+ public static bool operator ==(EquatableArray left, EquatableArray right)
+ {
+ return left.Equals(right);
+ }
+
+ ///
+ /// Checks whether two values are not the same.
+ ///
+ /// The first value.
+ /// The second value.
+ /// Whether and are not equal.
+ public static bool operator !=(EquatableArray left, EquatableArray right)
+ {
+ return !left.Equals(right);
+ }
+}
\ No newline at end of file
diff --git a/src/StronglyTypedIds/HashCode.cs b/src/StronglyTypedIds/HashCode.cs
new file mode 100644
index 000000000..4a2ca9ea3
--- /dev/null
+++ b/src/StronglyTypedIds/HashCode.cs
@@ -0,0 +1,383 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
+
+namespace StronglyTypedIds;
+
+///
+/// Polyfill for .NET 6 HashCode
+///
+internal struct HashCode
+{
+ private static readonly uint s_seed = GenerateGlobalSeed();
+
+ private const uint Prime1 = 2654435761U;
+ private const uint Prime2 = 2246822519U;
+ private const uint Prime3 = 3266489917U;
+ private const uint Prime4 = 668265263U;
+ private const uint Prime5 = 374761393U;
+
+ private uint _v1, _v2, _v3, _v4;
+ private uint _queue1, _queue2, _queue3;
+ private uint _length;
+
+ private static uint GenerateGlobalSeed()
+ {
+ var buffer = new byte[sizeof(uint)];
+ new Random().NextBytes(buffer);
+ return BitConverter.ToUInt32(buffer, 0);
+ }
+
+ public static int Combine(T1 value1)
+ {
+ // Provide a way of diffusing bits from something with a limited
+ // input hash space. For example, many enums only have a few
+ // possible hashes, only using the bottom few bits of the code. Some
+ // collections are built on the assumption that hashes are spread
+ // over a larger space, so diffusing the bits may help the
+ // collection work more efficiently.
+
+ uint hc1 = (uint)(value1?.GetHashCode() ?? 0);
+
+ uint hash = MixEmptyState();
+ hash += 4;
+
+ hash = QueueRound(hash, hc1);
+
+ hash = MixFinal(hash);
+ return (int)hash;
+ }
+
+ public static int Combine(T1 value1, T2 value2)
+ {
+ uint hc1 = (uint)(value1?.GetHashCode() ?? 0);
+ uint hc2 = (uint)(value2?.GetHashCode() ?? 0);
+
+ uint hash = MixEmptyState();
+ hash += 8;
+
+ hash = QueueRound(hash, hc1);
+ hash = QueueRound(hash, hc2);
+
+ hash = MixFinal(hash);
+ return (int)hash;
+ }
+
+ public static int Combine(T1 value1, T2 value2, T3 value3)
+ {
+ uint hc1 = (uint)(value1?.GetHashCode() ?? 0);
+ uint hc2 = (uint)(value2?.GetHashCode() ?? 0);
+ uint hc3 = (uint)(value3?.GetHashCode() ?? 0);
+
+ uint hash = MixEmptyState();
+ hash += 12;
+
+ hash = QueueRound(hash, hc1);
+ hash = QueueRound(hash, hc2);
+ hash = QueueRound(hash, hc3);
+
+ hash = MixFinal(hash);
+ return (int)hash;
+ }
+
+ public static int Combine(T1 value1, T2 value2, T3 value3, T4 value4)
+ {
+ uint hc1 = (uint)(value1?.GetHashCode() ?? 0);
+ uint hc2 = (uint)(value2?.GetHashCode() ?? 0);
+ uint hc3 = (uint)(value3?.GetHashCode() ?? 0);
+ uint hc4 = (uint)(value4?.GetHashCode() ?? 0);
+
+ Initialize(out uint v1, out uint v2, out uint v3, out uint v4);
+
+ v1 = Round(v1, hc1);
+ v2 = Round(v2, hc2);
+ v3 = Round(v3, hc3);
+ v4 = Round(v4, hc4);
+
+ uint hash = MixState(v1, v2, v3, v4);
+ hash += 16;
+
+ hash = MixFinal(hash);
+ return (int)hash;
+ }
+
+ public static int Combine(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5)
+ {
+ uint hc1 = (uint)(value1?.GetHashCode() ?? 0);
+ uint hc2 = (uint)(value2?.GetHashCode() ?? 0);
+ uint hc3 = (uint)(value3?.GetHashCode() ?? 0);
+ uint hc4 = (uint)(value4?.GetHashCode() ?? 0);
+ uint hc5 = (uint)(value5?.GetHashCode() ?? 0);
+
+ Initialize(out uint v1, out uint v2, out uint v3, out uint v4);
+
+ v1 = Round(v1, hc1);
+ v2 = Round(v2, hc2);
+ v3 = Round(v3, hc3);
+ v4 = Round(v4, hc4);
+
+ uint hash = MixState(v1, v2, v3, v4);
+ hash += 20;
+
+ hash = QueueRound(hash, hc5);
+
+ hash = MixFinal(hash);
+ return (int)hash;
+ }
+
+ public static int Combine(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6)
+ {
+ uint hc1 = (uint)(value1?.GetHashCode() ?? 0);
+ uint hc2 = (uint)(value2?.GetHashCode() ?? 0);
+ uint hc3 = (uint)(value3?.GetHashCode() ?? 0);
+ uint hc4 = (uint)(value4?.GetHashCode() ?? 0);
+ uint hc5 = (uint)(value5?.GetHashCode() ?? 0);
+ uint hc6 = (uint)(value6?.GetHashCode() ?? 0);
+
+ Initialize(out uint v1, out uint v2, out uint v3, out uint v4);
+
+ v1 = Round(v1, hc1);
+ v2 = Round(v2, hc2);
+ v3 = Round(v3, hc3);
+ v4 = Round(v4, hc4);
+
+ uint hash = MixState(v1, v2, v3, v4);
+ hash += 24;
+
+ hash = QueueRound(hash, hc5);
+ hash = QueueRound(hash, hc6);
+
+ hash = MixFinal(hash);
+ return (int)hash;
+ }
+
+ public static int Combine(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6, T7 value7)
+ {
+ uint hc1 = (uint)(value1?.GetHashCode() ?? 0);
+ uint hc2 = (uint)(value2?.GetHashCode() ?? 0);
+ uint hc3 = (uint)(value3?.GetHashCode() ?? 0);
+ uint hc4 = (uint)(value4?.GetHashCode() ?? 0);
+ uint hc5 = (uint)(value5?.GetHashCode() ?? 0);
+ uint hc6 = (uint)(value6?.GetHashCode() ?? 0);
+ uint hc7 = (uint)(value7?.GetHashCode() ?? 0);
+
+ Initialize(out uint v1, out uint v2, out uint v3, out uint v4);
+
+ v1 = Round(v1, hc1);
+ v2 = Round(v2, hc2);
+ v3 = Round(v3, hc3);
+ v4 = Round(v4, hc4);
+
+ uint hash = MixState(v1, v2, v3, v4);
+ hash += 28;
+
+ hash = QueueRound(hash, hc5);
+ hash = QueueRound(hash, hc6);
+ hash = QueueRound(hash, hc7);
+
+ hash = MixFinal(hash);
+ return (int)hash;
+ }
+
+ public static int Combine(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6, T7 value7, T8 value8)
+ {
+ uint hc1 = (uint)(value1?.GetHashCode() ?? 0);
+ uint hc2 = (uint)(value2?.GetHashCode() ?? 0);
+ uint hc3 = (uint)(value3?.GetHashCode() ?? 0);
+ uint hc4 = (uint)(value4?.GetHashCode() ?? 0);
+ uint hc5 = (uint)(value5?.GetHashCode() ?? 0);
+ uint hc6 = (uint)(value6?.GetHashCode() ?? 0);
+ uint hc7 = (uint)(value7?.GetHashCode() ?? 0);
+ uint hc8 = (uint)(value8?.GetHashCode() ?? 0);
+
+ Initialize(out uint v1, out uint v2, out uint v3, out uint v4);
+
+ v1 = Round(v1, hc1);
+ v2 = Round(v2, hc2);
+ v3 = Round(v3, hc3);
+ v4 = Round(v4, hc4);
+
+ v1 = Round(v1, hc5);
+ v2 = Round(v2, hc6);
+ v3 = Round(v3, hc7);
+ v4 = Round(v4, hc8);
+
+ uint hash = MixState(v1, v2, v3, v4);
+ hash += 32;
+
+ hash = MixFinal(hash);
+ return (int)hash;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void Initialize(out uint v1, out uint v2, out uint v3, out uint v4)
+ {
+ v1 = s_seed + Prime1 + Prime2;
+ v2 = s_seed + Prime2;
+ v3 = s_seed;
+ v4 = s_seed - Prime1;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static uint Round(uint hash, uint input)
+ {
+ return RotateLeft(hash + input * Prime2, 13) * Prime1;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static uint QueueRound(uint hash, uint queuedValue)
+ {
+ return RotateLeft(hash + queuedValue * Prime3, 17) * Prime4;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static uint MixState(uint v1, uint v2, uint v3, uint v4)
+ {
+ return RotateLeft(v1, 1) + RotateLeft(v2, 7) + RotateLeft(v3, 12) + RotateLeft(v4, 18);
+ }
+
+ private static uint MixEmptyState()
+ {
+ return s_seed + Prime5;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static uint MixFinal(uint hash)
+ {
+ hash ^= hash >> 15;
+ hash *= Prime2;
+ hash ^= hash >> 13;
+ hash *= Prime3;
+ hash ^= hash >> 16;
+ return hash;
+ }
+
+ public void Add(T value)
+ {
+ Add(value?.GetHashCode() ?? 0);
+ }
+
+ public void Add(T value, IEqualityComparer? comparer)
+ {
+ Add(value is null ? 0 : (comparer?.GetHashCode(value) ?? value.GetHashCode()));
+ }
+
+ private void Add(int value)
+ {
+ // The original xxHash works as follows:
+ // 0. Initialize immediately. We can't do this in a struct (no
+ // default ctor).
+ // 1. Accumulate blocks of length 16 (4 uints) into 4 accumulators.
+ // 2. Accumulate remaining blocks of length 4 (1 uint) into the
+ // hash.
+ // 3. Accumulate remaining blocks of length 1 into the hash.
+
+ // There is no need for #3 as this type only accepts ints. _queue1,
+ // _queue2 and _queue3 are basically a buffer so that when
+ // ToHashCode is called we can execute #2 correctly.
+
+ // We need to initialize the xxHash32 state (_v1 to _v4) lazily (see
+ // #0) nd the last place that can be done if you look at the
+ // original code is just before the first block of 16 bytes is mixed
+ // in. The xxHash32 state is never used for streams containing fewer
+ // than 16 bytes.
+
+ // To see what's really going on here, have a look at the Combine
+ // methods.
+
+ uint val = (uint)value;
+
+ // Storing the value of _length locally shaves of quite a few bytes
+ // in the resulting machine code.
+ uint previousLength = _length++;
+ uint position = previousLength % 4;
+
+ // Switch can't be inlined.
+
+ if (position == 0)
+ _queue1 = val;
+ else if (position == 1)
+ _queue2 = val;
+ else if (position == 2)
+ _queue3 = val;
+ else // position == 3
+ {
+ if (previousLength == 3)
+ Initialize(out _v1, out _v2, out _v3, out _v4);
+
+ _v1 = Round(_v1, _queue1);
+ _v2 = Round(_v2, _queue2);
+ _v3 = Round(_v3, _queue3);
+ _v4 = Round(_v4, val);
+ }
+ }
+
+ public int ToHashCode()
+ {
+ // Storing the value of _length locally shaves of quite a few bytes
+ // in the resulting machine code.
+ uint length = _length;
+
+ // position refers to the *next* queue position in this method, so
+ // position == 1 means that _queue1 is populated; _queue2 would have
+ // been populated on the next call to Add.
+ uint position = length % 4;
+
+ // If the length is less than 4, _v1 to _v4 don't contain anything
+ // yet. xxHash32 treats this differently.
+
+ uint hash = length < 4 ? MixEmptyState() : MixState(_v1, _v2, _v3, _v4);
+
+ // _length is incremented once per Add(Int32) and is therefore 4
+ // times too small (xxHash length is in bytes, not ints).
+
+ hash += length * 4;
+
+ // Mix what remains in the queue
+
+ // Switch can't be inlined right now, so use as few branches as
+ // possible by manually excluding impossible scenarios (position > 1
+ // is always false if position is not > 0).
+ if (position > 0)
+ {
+ hash = QueueRound(hash, _queue1);
+ if (position > 1)
+ {
+ hash = QueueRound(hash, _queue2);
+ if (position > 2)
+ hash = QueueRound(hash, _queue3);
+ }
+ }
+
+ hash = MixFinal(hash);
+ return (int)hash;
+ }
+
+#pragma warning disable 0809
+ // Obsolete member 'memberA' overrides non-obsolete member 'memberB'.
+ // Disallowing GetHashCode and Equals is by design
+
+ // * We decided to not override GetHashCode() to produce the hash code
+ // as this would be weird, both naming-wise as well as from a
+ // behavioral standpoint (GetHashCode() should return the object's
+ // hash code, not the one being computed).
+
+ // * Even though ToHashCode() can be called safely multiple times on
+ // this implementation, it is not part of the contract. If the
+ // implementation has to change in the future we don't want to worry
+ // about people who might have incorrectly used this type.
+
+ [Obsolete("HashCode is a mutable struct and should not be compared with other HashCodes. Use ToHashCode to retrieve the computed hash code.", error: true)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override int GetHashCode() => throw new NotSupportedException("Hash code not supported");
+
+ [Obsolete("HashCode is a mutable struct and should not be compared with other HashCodes.", error: true)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override bool Equals(object? obj) => throw new NotSupportedException("Equality not supported");
+#pragma warning restore 0809
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static uint RotateLeft(uint value, int offset)
+ => (value << offset) | (value >> (32 - offset));
+}
\ No newline at end of file
diff --git a/src/StronglyTypedIds/ParentClass.cs b/src/StronglyTypedIds/ParentClass.cs
deleted file mode 100644
index 012c41274..000000000
--- a/src/StronglyTypedIds/ParentClass.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace StronglyTypedIds;
-
-internal class ParentClass
-{
- public ParentClass(string keyword, string name, string constraints, ParentClass? child)
- {
- Keyword = keyword;
- Name = name;
- Constraints = constraints;
- Child = child;
- }
-
- public ParentClass? Child { get; }
- public string Keyword { get; }
- public string Name { get; }
- public string Constraints { get; }
-}
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Parser.cs b/src/StronglyTypedIds/Parser.cs
index 39fc96f93..2f4162f89 100644
--- a/src/StronglyTypedIds/Parser.cs
+++ b/src/StronglyTypedIds/Parser.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Collections.Immutable;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
@@ -14,356 +13,294 @@ internal static class Parser
public const string StronglyTypedIdAttribute = "StronglyTypedIds.StronglyTypedIdAttribute";
public const string StronglyTypedIdDefaultsAttribute = "StronglyTypedIds.StronglyTypedIdDefaultsAttribute";
- public static bool IsStructTargetForGeneration(SyntaxNode node)
- => node is StructDeclarationSyntax m && m.AttributeLists.Count > 0;
-
- public static bool IsAttributeTargetForGeneration(SyntaxNode node)
- => node is AttributeListSyntax attributeList
- && attributeList.Target is not null
- && attributeList.Target.Identifier.IsKind(SyntaxKind.AssemblyKeyword);
-
- public static StructDeclarationSyntax? GetStructSemanticTargetForGeneration(GeneratorSyntaxContext context)
+ public static Result<(StructToGenerate info, bool valid)> GetStructSemanticTarget(GeneratorAttributeSyntaxContext ctx, CancellationToken ct)
{
- // we know the node is a EnumDeclarationSyntax thanks to IsSyntaxTargetForGeneration
- var structDeclarationSyntax = (StructDeclarationSyntax)context.Node;
-
- // loop through all the attributes on the method
- foreach (AttributeListSyntax attributeListSyntax in structDeclarationSyntax.AttributeLists)
+ var structSymbol = ctx.TargetSymbol as INamedTypeSymbol;
+ if (structSymbol is null)
{
- foreach (AttributeSyntax attributeSyntax in attributeListSyntax.Attributes)
- {
- if (ModelExtensions.GetSymbolInfo(context.SemanticModel, attributeSyntax).Symbol is not IMethodSymbol attributeSymbol)
- {
- // weird, we couldn't get the symbol, ignore it
- continue;
- }
-
- INamedTypeSymbol attributeContainingTypeSymbol = attributeSymbol.ContainingType;
- string fullName = attributeContainingTypeSymbol.ToDisplayString();
-
- // Is the attribute the [StronglyTypedId] attribute?
- if (fullName == StronglyTypedIdAttribute)
- {
- // return the enum
- return structDeclarationSyntax;
- }
- }
+ return Result.Fail();
}
- // we didn't find the attribute we were looking for
- return null;
- }
+ var structSyntax = (StructDeclarationSyntax)ctx.TargetNode;
- public static AttributeSyntax? GetAssemblyAttributeSemanticTargetForGeneration(GeneratorSyntaxContext context)
- {
- // we know the node is a AttributeListSyntax thanks to IsSyntaxTargetForGeneration
- var attributeListSyntax = (AttributeListSyntax)context.Node;
+ var hasMisconfiguredInput = false;
+ List? diagnostics = null;
+ Template? template = null;
+ string[]? templateNames = null;
+ LocationInfo? attributeLocation = null;
- // loop through all the attributes in the list
- foreach (AttributeSyntax attributeSyntax in attributeListSyntax.Attributes)
+ foreach (AttributeData attribute in structSymbol.GetAttributes())
{
- if (ModelExtensions.GetSymbolInfo(context.SemanticModel, attributeSyntax).Symbol is not IMethodSymbol attributeSymbol)
+ if (!((attribute.AttributeClass?.Name == "StronglyTypedIdAttribute" ||
+ attribute.AttributeClass?.Name == "StronglyTypedId") &&
+ attribute.AttributeClass.ToDisplayString() == StronglyTypedIdAttribute))
{
- // weird, we couldn't get the symbol, ignore it
+ // wrong attribute
continue;
}
- INamedTypeSymbol attributeContainingTypeSymbol = attributeSymbol.ContainingType;
- string fullName = attributeContainingTypeSymbol.ToDisplayString();
+ (var result, (template, templateNames)) = GetConstructorValues(attribute);
+ hasMisconfiguredInput |= result;
- // Is the attribute the [StronglyTypedIdDefaultsAttribute] attribute?
- if (fullName == StronglyTypedIdDefaultsAttribute)
+ if (attribute.ApplicationSyntaxReference?.GetSyntax() is { } s)
{
- // return the attribute
- return attributeSyntax;
+ attributeLocation = LocationInfo.CreateFrom(s);
}
}
- // we didn't find the attribute we were looking for
- return null;
- }
-
- public static List<(string Name, string NameSpace, StronglyTypedIdConfiguration Config, ParentClass? Parent)> GetTypesToGenerate(
- Compilation compilation,
- ImmutableArray targets,
- Action reportDiagnostic,
- CancellationToken ct)
- {
- var idsToGenerate = new List<(string Name, string NameSpace, StronglyTypedIdConfiguration Config, ParentClass? Parent)>();
- INamedTypeSymbol? idAttribute = compilation.GetTypeByMetadataName(StronglyTypedIdAttribute);
- if (idAttribute == null)
+ var hasPartialModifier = false;
+ foreach (var modifier in structSyntax.Modifiers)
{
- // nothing to do if this type isn't available
- return idsToGenerate;
- }
-
- foreach (StructDeclarationSyntax structDeclarationSyntax in targets)
- {
- // stop if we're asked to
- ct.ThrowIfCancellationRequested();
-
- SemanticModel semanticModel = compilation.GetSemanticModel(structDeclarationSyntax.SyntaxTree);
- if (semanticModel.GetDeclaredSymbol(structDeclarationSyntax) is not INamedTypeSymbol structSymbol)
+ if (modifier.IsKind(SyntaxKind.PartialKeyword))
{
- // something went wrong
- continue;
+ hasPartialModifier = true;
+ break;
}
+ }
- StronglyTypedIdConfiguration? config = null;
- var hasMisconfiguredInput = false;
-
- foreach (AttributeData attribute in structSymbol.GetAttributes())
- {
- if (!idAttribute.Equals(attribute.AttributeClass, SymbolEqualityComparer.Default))
- {
- continue;
- }
-
- StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default;
- StronglyTypedIdConverter converter = StronglyTypedIdConverter.Default;
- StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default;
-
- if (!attribute.ConstructorArguments.IsEmpty)
- {
- // make sure we don't have any errors
- ImmutableArray args = attribute.ConstructorArguments;
-
- foreach (TypedConstant arg in args)
- {
- if (arg.Kind == TypedConstantKind.Error)
- {
- // have an error, so don't try and do any generation
- hasMisconfiguredInput = true;
- }
- }
-
- switch (args.Length)
- {
- case 3:
- implementations = (StronglyTypedIdImplementations)args[2].Value!;
- goto case 2;
- case 2:
- converter = (StronglyTypedIdConverter)args[1].Value!;
- goto case 1;
- case 1:
- backingType = (StronglyTypedIdBackingType)args[0].Value!;
- break;
- }
- }
-
- if (!attribute.NamedArguments.IsEmpty)
- {
- foreach (KeyValuePair arg in attribute.NamedArguments)
- {
- TypedConstant typedConstant = arg.Value;
- if (typedConstant.Kind == TypedConstantKind.Error)
- {
- hasMisconfiguredInput = true;
- }
- else
- {
- switch (arg.Key)
- {
- case "backingType":
- backingType = (StronglyTypedIdBackingType)typedConstant.Value!;
- break;
- case "converters":
- converter = (StronglyTypedIdConverter)typedConstant.Value!;
- break;
- case "implementations":
- implementations = (StronglyTypedIdImplementations)typedConstant.Value!;
- break;
- }
- }
- }
+ if (!hasPartialModifier)
+ {
+ diagnostics ??= new();
+ diagnostics.Add(NotPartialDiagnostic.CreateInfo(structSyntax));
+ }
+ var errors = diagnostics is null
+ ? EquatableArray.Empty
+ : new EquatableArray(diagnostics.ToArray());
- }
+ if (hasMisconfiguredInput)
+ {
+ return new Result<(StructToGenerate, bool)>((default, false), errors);
+ }
- if (hasMisconfiguredInput)
- {
- // skip further generator execution and let compiler generate the errors
- break;
- }
+ string nameSpace = GetNameSpace(structSyntax);
+ ParentClass? parentClass = GetParentClasses(structSyntax);
+ var name = structSymbol.Name;
- if (!converter.IsValidFlags())
- {
- reportDiagnostic(InvalidConverterDiagnostic.Create(structDeclarationSyntax));
- }
+ var toGenerate =new StructToGenerate(
+ name: name,
+ nameSpace: nameSpace,
+ template: template,
+ templateNames: templateNames,
+ templateLocation: attributeLocation!,
+ parent: parentClass);
- if (!Enum.IsDefined(typeof(StronglyTypedIdBackingType), backingType))
- {
- reportDiagnostic(InvalidBackingTypeDiagnostic.Create(structDeclarationSyntax));
- }
+ return new Result<(StructToGenerate, bool)>((toGenerate, true), errors);
+ }
- if (!implementations.IsValidFlags())
- {
- reportDiagnostic(InvalidImplementationsDiagnostic.Create(structDeclarationSyntax));
- }
+ public static Result<(Defaults defaults, bool valid)> GetDefaults(
+ GeneratorAttributeSyntaxContext ctx, CancellationToken ct)
+ {
+ var assemblyAttributes = ctx.TargetSymbol.GetAttributes();
+ if (assemblyAttributes.IsDefaultOrEmpty)
+ {
+ return Result.Fail();
+ }
- config = new StronglyTypedIdConfiguration(backingType, converter, implementations);
- break;
- }
+ // We only return the first config that we find
+ string[]? templateNames = null;
+ Template? template = null;
+ LocationInfo? attributeLocation = null;
+ List? diagnostics = null;
+ bool hasMisconfiguredInput = false;
+ bool hasMultiple = false;
- if (config is null || hasMisconfiguredInput)
+ // if we have multiple attributes we still check them, so that we can add extra diagnostics if necessary
+ // the "first" one found won't be flagged as a duplicate though.
+ foreach (AttributeData attribute in assemblyAttributes)
+ {
+ if (!((attribute.AttributeClass?.Name == "StronglyTypedIdDefaultsAttribute" ||
+ attribute.AttributeClass?.Name == "StronglyTypedIdDefaults") &&
+ attribute.AttributeClass.ToDisplayString() == StronglyTypedIdDefaultsAttribute))
{
- continue; // name clash, or error
+ // wrong attribute
+ continue;
}
- var hasPartialModifier = false;
- foreach (var modifier in structDeclarationSyntax.Modifiers)
+ var syntax = attribute.ApplicationSyntaxReference?.GetSyntax();
+ if (templateNames is not null || template.HasValue || hasMisconfiguredInput)
{
- if (modifier.IsKind(SyntaxKind.PartialKeyword))
+ hasMultiple = true;
+ if (syntax is not null)
{
- hasPartialModifier = true;
- break;
+ diagnostics ??= new();
+ diagnostics.Add(MultipleAssemblyAttributeDiagnostic.CreateInfo(syntax));
}
}
- if (!hasPartialModifier)
+ (var result, (template, templateNames)) = GetConstructorValues(attribute);
+ hasMisconfiguredInput |= result;
+
+ if (syntax is not null)
{
- reportDiagnostic(NotPartialDiagnostic.Create(structDeclarationSyntax));
+ attributeLocation = LocationInfo.CreateFrom(syntax);
}
+ }
- string nameSpace = GetNameSpace(structDeclarationSyntax);
- var parentClass = GetParentClasses(structDeclarationSyntax);
- var name = structSymbol.Name;
+ var errors = diagnostics is null
+ ? EquatableArray.Empty
+ : new EquatableArray(diagnostics.ToArray());
- idsToGenerate.Add((Name: name, NameSpace: nameSpace, Config: config.Value, Parent: parentClass));
+ if (hasMisconfiguredInput)
+ {
+ return new Result<(Defaults, bool)>((default, false), errors);
}
- return idsToGenerate;
+ var defaults = new Defaults(template, templateNames, attributeLocation!, hasMultiple);
+
+ return new Result<(Defaults, bool)>((defaults, true), errors);
}
- public static StronglyTypedIdConfiguration? GetDefaults(
- ImmutableArray defaults,
- Compilation compilation,
- Action reportDiagnostic)
+ private static (bool HasMisconfiguredInput, (Template? Template, string[]? TemplateNames)) GetConstructorValues(AttributeData attribute)
{
- if (defaults.IsDefaultOrEmpty)
- {
- // No global defaults
- return null;
- }
+ (Template? Template, string? Name, string[]? Names)? results1 = null;
+ (Template? Template, string? Name, string[]? Names)? results2 = null;
- var assemblyAttributes = compilation.Assembly.GetAttributes();
- if (assemblyAttributes.IsDefaultOrEmpty)
+ if (attribute.ConstructorArguments is { IsEmpty: false } args)
{
- return null;
- }
+ // we should have at most 2 args (params count as one arg)
+ if (args.Length > 2)
+ {
+ // have an error, so don't try and do any generation
+ return (true, default);
+ }
- INamedTypeSymbol? defaultsAttribute = compilation.GetTypeByMetadataName(StronglyTypedIdDefaultsAttribute);
- if (defaultsAttribute is null)
- {
- // The attribute isn't part of the compilation for some reason...
- return null;
- }
+ // Should always have at least one arg, but it might be an empty array
+ var (success, results) = TryGetTypedConstant(args[0]);
- foreach (AttributeData attribute in assemblyAttributes)
- {
- if (!defaultsAttribute.Equals(attribute.AttributeClass, SymbolEqualityComparer.Default))
+ if (success)
{
- continue;
+ results1 = results;
+ }
+ else
+ {
+ // have an error, so don't try and do any generation
+ return (true, default);
}
- StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default;
- StronglyTypedIdConverter converter = StronglyTypedIdConverter.Default;
- StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default;
- bool hasMisconfiguredInput = false;
-
- if (!attribute.ConstructorArguments.IsEmpty)
+ if (args.Length == 2)
{
- // make sure we don't have any errors
- ImmutableArray args = attribute.ConstructorArguments;
+ (success, results) = TryGetTypedConstant(args[1]);
- foreach (TypedConstant arg in args)
+ if (success)
{
- if (arg.Kind == TypedConstantKind.Error)
- {
- // have an error, so don't try and do any generation
- hasMisconfiguredInput = true;
- }
+ results2 = results;
}
-
- switch (args.Length)
+ else
{
- case 3:
- implementations = (StronglyTypedIdImplementations)args[2].Value!;
- goto case 2;
- case 2:
- converter = (StronglyTypedIdConverter)args[1].Value!;
- goto case 1;
- case 1:
- backingType = (StronglyTypedIdBackingType)args[0].Value!;
- break;
+ // have an error, so don't try and do any generation
+ return (true, default);
}
}
-
- if (!attribute.NamedArguments.IsEmpty)
+ }
+
+ if (attribute.NamedArguments is { IsEmpty: false } namedArgs)
+ {
+ foreach (KeyValuePair arg in namedArgs)
{
- foreach (KeyValuePair arg in attribute.NamedArguments)
+ // Should always have at least one arg, but it might be an empty array
+ var (success, results) = TryGetTypedConstant(arg.Value);
+
+ if (success)
{
- TypedConstant typedConstant = arg.Value;
- if (typedConstant.Kind == TypedConstantKind.Error)
+ if (results1 is null)
+ {
+ results1 = results;
+ }
+ else if(results2 is null)
{
- hasMisconfiguredInput = true;
+ results2 = results;
}
else
{
- switch (arg.Key)
- {
- case "backingType":
- backingType = (StronglyTypedIdBackingType)typedConstant.Value!;
- break;
- case "converters":
- converter = (StronglyTypedIdConverter)typedConstant.Value!;
- break;
- case "implementations":
- implementations = (StronglyTypedIdImplementations)typedConstant.Value!;
- break;
- }
+ // must be an error
+ return (true, default);
}
}
+ else
+ {
+ // have an error, so don't try and do any generation
+ return (true, default);
+ }
+ }
+ }
+
+
+ // consolidate
+ var template = results1?.Template ?? results2?.Template;
+ var name = results1?.Name ?? results2?.Name;
+ var names = results1?.Names ?? results2?.Names;
+
+ if (name is not null)
+ {
+ if (names is {Length: > 0} ns)
+ {
+ names = new string[ns.Length + 1];
+ ns.CopyTo(names, 0);
+ names[^1] = name;
+ }
+ else
+ {
+ names = new[] {name};
}
+ }
+
+ return (false, (template, names));
- if (hasMisconfiguredInput)
+ static (bool IsValid, (Template? Template, string? Name, string[]? Names)) TryGetTypedConstant(in TypedConstant arg)
+ {
+ if (arg.Kind is TypedConstantKind.Error)
{
- // skip further generator execution and let compiler generate the errors
- break;
+ return (false, default);
}
- SyntaxNode? syntax = null;
- if (!converter.IsValidFlags())
+ if (arg.Kind is TypedConstantKind.Primitive
+ && arg.Value is string stringValue)
{
- syntax = attribute.ApplicationSyntaxReference?.GetSyntax();
- if (syntax is not null)
- {
- reportDiagnostic(InvalidConverterDiagnostic.Create(syntax));
- }
+ var name = string.IsNullOrWhiteSpace(stringValue)
+ ? string.Empty
+ : stringValue;
+
+ return (true, (null, name, null));
}
- if (!Enum.IsDefined(typeof(StronglyTypedIdBackingType), backingType))
+ if (arg.Kind is TypedConstantKind.Enum
+ && arg.Value is int intValue)
{
- syntax ??= attribute.ApplicationSyntaxReference?.GetSyntax();
- if (syntax is not null)
- {
- reportDiagnostic(InvalidBackingTypeDiagnostic.Create(syntax));
- }
+ return (true, ((Template) intValue, null, null));
}
- if (!implementations.IsValidFlags())
+ if (arg.Kind is TypedConstantKind.Array)
{
- syntax ??= attribute.ApplicationSyntaxReference?.GetSyntax();
- if (syntax is not null)
+ var values = arg.Values;
+
+ // if null is passed, it's treated the same as an empty array
+ if (values.IsDefaultOrEmpty)
+ {
+ return (true, (null, null, Array.Empty()));
+ }
+
+ var names = new string[values.Length];
+ for (var i = 0; i < values.Length; i++)
{
- reportDiagnostic(InvalidImplementationsDiagnostic.Create(syntax));
+ if (values[i].Kind == TypedConstantKind.Error)
+ {
+ // Abandon generation
+ return (false, default);
+ }
+
+ var value = values[i].Value as string;
+ names[i] = string.IsNullOrWhiteSpace(value)
+ ? string.Empty
+ : value!;
}
+
+ return (true, (null, null, names));
}
- return new StronglyTypedIdConfiguration(backingType, converter, implementations);
+ // Some other type, weird, shouldn't be able to get this
+ return (false, default);
}
-
- return null;
}
private static string GetNameSpace(StructDeclarationSyntax structSymbol)
@@ -403,11 +340,22 @@ potentialNamespaceParent is not NamespaceDeclarationSyntax
while (parentIdClass != null && IsAllowedKind(parentIdClass.Kind()))
{
+ var keyword = parentIdClass is RecordDeclarationSyntax record
+ ? record.ClassOrStructKeyword.Kind() switch
+ {
+ SyntaxKind.StructKeyword => "record struct",
+ SyntaxKind.ClassKeyword => "record class",
+ _ => "record",
+ }
+ : parentIdClass.Keyword.ValueText;
+
parentClass = new ParentClass(
- keyword: parentIdClass.Keyword.ValueText,
- name: parentIdClass.Identifier.ToString() + parentIdClass.TypeParameterList,
- constraints: parentIdClass.ConstraintClauses.ToString(),
- child: parentClass);
+ Modifiers: parentIdClass.Modifiers.ToString(),
+ Keyword: keyword,
+ Name: parentIdClass.Identifier.ToString() + parentIdClass.TypeParameterList,
+ Constraints: parentIdClass.ConstraintClauses.ToString(),
+ Child: parentClass,
+ IsGeneric: parentIdClass.Arity > 0);
parentIdClass = (parentIdClass.Parent as TypeDeclarationSyntax);
}
@@ -417,6 +365,7 @@ potentialNamespaceParent is not NamespaceDeclarationSyntax
static bool IsAllowedKind(SyntaxKind kind) =>
kind == SyntaxKind.ClassDeclaration ||
kind == SyntaxKind.StructDeclaration ||
+ kind == SyntaxKind.RecordStructDeclaration ||
kind == SyntaxKind.RecordDeclaration;
}
}
\ No newline at end of file
diff --git a/src/StronglyTypedIds/SourceGenerationHelper.cs b/src/StronglyTypedIds/SourceGenerationHelper.cs
index e33515310..af784f95a 100644
--- a/src/StronglyTypedIds/SourceGenerationHelper.cs
+++ b/src/StronglyTypedIds/SourceGenerationHelper.cs
@@ -1,5 +1,4 @@
using System;
-using System.Collections.Generic;
using System.Text;
namespace StronglyTypedIds
@@ -10,41 +9,8 @@ public static string CreateId(
string idNamespace,
string idName,
ParentClass? parentClass,
- StronglyTypedIdConverter converters,
- StronglyTypedIdBackingType backingType,
- StronglyTypedIdImplementations implementations)
- => CreateId(idNamespace, idName, parentClass, converters, backingType, implementations, null);
-
- public static string CreateId(
- string idNamespace,
- string idName,
- ParentClass? parentClass,
- StronglyTypedIdConverter converters,
- StronglyTypedIdBackingType backingType,
- StronglyTypedIdImplementations implementations,
- StringBuilder? sb)
- {
- var resources = backingType switch
- {
- StronglyTypedIdBackingType.Guid => EmbeddedSources.GuidResources,
- StronglyTypedIdBackingType.Int => EmbeddedSources.IntResources,
- StronglyTypedIdBackingType.Long => EmbeddedSources.LongResources,
- StronglyTypedIdBackingType.String => EmbeddedSources.StringResources,
- StronglyTypedIdBackingType.NullableString => EmbeddedSources.NullableStringResources,
- StronglyTypedIdBackingType.MassTransitNewId => EmbeddedSources.NewIdResources,
- _ => throw new ArgumentException("Unknown backing type: " + backingType, nameof(backingType)),
- };
-
- return CreateId(idNamespace, idName, parentClass, converters, implementations, resources, sb);
- }
-
- static string CreateId(
- string idNamespace,
- string idName,
- ParentClass? parentClass,
- StronglyTypedIdConverter converters,
- StronglyTypedIdImplementations implementations,
- EmbeddedSources.ResourceCollection resources,
+ string template,
+ bool addDefaultAttributes,
StringBuilder? sb)
{
if (string.IsNullOrEmpty(idName))
@@ -52,36 +18,20 @@ static string CreateId(
throw new ArgumentException("Value cannot be null or empty.", nameof(idName));
}
- if (converters == StronglyTypedIdConverter.Default)
- {
- throw new ArgumentException("Cannot use default converter - must provide concrete values or None", nameof(converters));
- }
-
- if (implementations == StronglyTypedIdImplementations.Default)
- {
- throw new ArgumentException("Cannot use default implementations - must provide concrete values or None", nameof(implementations));
- }
-
var hasNamespace = !string.IsNullOrEmpty(idNamespace);
- var useTypeConverter = converters.IsSet(StronglyTypedIdConverter.TypeConverter);
- var useNewtonsoftJson = converters.IsSet(StronglyTypedIdConverter.NewtonsoftJson);
- var useSystemTextJson = converters.IsSet(StronglyTypedIdConverter.SystemTextJson);
- var useEfCoreValueConverter = converters.IsSet(StronglyTypedIdConverter.EfCoreValueConverter);
- var useDapperTypeHandler = converters.IsSet(StronglyTypedIdConverter.DapperTypeHandler);
-
- var useIEquatable = implementations.IsSet(StronglyTypedIdImplementations.IEquatable);
- var useIComparable = implementations.IsSet(StronglyTypedIdImplementations.IComparable);
-
var parentsCount = 0;
- sb ??= new StringBuilder();
- sb.Append(resources.Header);
-
- if (resources.NullableEnable)
+ if (sb is null)
{
- sb.AppendLine("#nullable enable");
+ sb = new StringBuilder();
}
+ else
+ {
+ sb.Clear();
+ }
+
+ sb.Append(EmbeddedSources.AutoGeneratedHeader);
if (hasNamespace)
{
@@ -92,73 +42,43 @@ static string CreateId(
{");
}
- while (parentClass is not null)
+ var hasGenericParent = false;
+ while (parentClass is { } parent)
{
+ sb.Append(" ");
+
+ if (!string.IsNullOrEmpty(parent.Modifiers))
+ {
+ sb.Append(parent.Modifiers).Append(' ');
+ }
+
+ if (parent.Modifiers.IndexOf("partial", StringComparison.Ordinal) == -1)
+ {
+ sb.Append("partial ");
+ }
+
sb
- .Append(" partial ")
- .Append(parentClass.Keyword)
+ .Append(parent.Keyword)
.Append(' ')
- .Append(parentClass.Name)
+ .Append(parent.Name)
.Append(' ')
- .Append(parentClass.Constraints)
+ .Append(parent.Constraints)
.AppendLine(@"
{");
parentsCount++;
- parentClass = parentClass.Child;
+ hasGenericParent |= parent.IsGeneric;
+ parentClass = parent.Child;
}
-
- if (useNewtonsoftJson)
+
+ if (addDefaultAttributes && !hasGenericParent)
{
- sb.AppendLine(EmbeddedSources.NewtonsoftJsonAttributeSource);
+ sb.AppendLine(" [global::System.ComponentModel.TypeConverter(typeof(PLACEHOLDERIDTypeConverter))]");
+ sb.AppendLine(" [global::System.Text.Json.Serialization.JsonConverter(typeof(PLACEHOLDERIDSystemTextJsonConverter))]");
}
- if (useSystemTextJson)
- {
- sb.AppendLine(EmbeddedSources.SystemTextJsonAttributeSource);
- }
+ sb.AppendLine(template);
- if (useTypeConverter)
- {
- sb.AppendLine(EmbeddedSources.TypeConverterAttributeSource);
- }
-
- sb.Append(resources.BaseId);
- ReplaceInterfaces(sb, useIEquatable, useIComparable);
-
- // IEquatable is already implemented whether or not the interface is implemented
-
- if (useIComparable)
- {
- sb.AppendLine(resources.Comparable);
- }
-
- if (useEfCoreValueConverter)
- {
- sb.AppendLine(resources.EfCoreValueConverter);
- }
-
- if (useDapperTypeHandler)
- {
- sb.AppendLine(resources.DapperTypeHandler);
- }
-
- if (useTypeConverter)
- {
- sb.AppendLine(resources.TypeConverter);
- }
-
- if (useNewtonsoftJson)
- {
- sb.AppendLine(resources.Newtonsoft);
- }
-
- if (useSystemTextJson)
- {
- sb.AppendLine(resources.SystemTextJson);
- }
-
- sb.Replace("TESTID", idName);
- sb.AppendLine(@" }");
+ sb.Replace("PLACEHOLDERID", idName);
for (int i = 0; i < parentsCount; i++)
{
@@ -173,44 +93,28 @@ static string CreateId(
return sb.ToString();
}
- private static void ReplaceInterfaces(StringBuilder sb, bool useIEquatable, bool useIComparable)
+ internal static string CreateSourceName(StringBuilder sb, string nameSpace, ParentClass? parent, string name, string template)
{
- var interfaces = new List();
-
- if (useIComparable)
- {
- interfaces.Add("System.IComparable");
- }
-
- if (useIEquatable)
- {
- interfaces.Add("System.IEquatable");
- }
-
- if (interfaces.Count > 0)
- {
- sb.Replace("INTERFACES", string.Join(", ", interfaces));
- }
- else
+ sb.Clear();
+ sb.Append(nameSpace).Append('.');
+ while (parent is { } p)
{
- sb.Replace(": INTERFACES", string.Empty);
- }
- }
-
- internal static string CreateSourceName(string nameSpace, ParentClass? parent, string name)
- {
- var sb = new StringBuilder(nameSpace).Append('.');
- while (parent != null)
- {
- var s = parent.Name
+ var s = p.Name
.Replace(" ", "")
.Replace(",", "")
.Replace("<", "__")
.Replace(">", "");
sb.Append(s).Append('.');
- parent = parent.Child;
+ parent = p.Child;
+ }
+
+ sb.Append(name);
+ if (!string.IsNullOrEmpty(template))
+ {
+ sb.Append('.').Append(template);
}
- return sb.Append(name).Append(".g.cs").ToString();
+
+ return sb.Append(".g.cs").ToString();
}
}
}
diff --git a/src/StronglyTypedIds/StronglyTypedIdConfiguration.cs b/src/StronglyTypedIds/StronglyTypedIdConfiguration.cs
deleted file mode 100644
index 0c4860cd2..000000000
--- a/src/StronglyTypedIds/StronglyTypedIdConfiguration.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-
-namespace StronglyTypedIds
-{
- internal readonly struct StronglyTypedIdConfiguration
- {
- public StronglyTypedIdBackingType BackingType { get; }
-
- public StronglyTypedIdConverter Converters { get; }
-
- public StronglyTypedIdImplementations Implementations { get; }
-
- public StronglyTypedIdConfiguration(
- StronglyTypedIdBackingType backingType,
- StronglyTypedIdConverter converters,
- StronglyTypedIdImplementations implementations)
- {
- BackingType = backingType;
- Converters = converters;
- Implementations = implementations;
- }
-
- ///
- /// Gets the default values for when a default attribute is not used.
- /// Should be kept in sync with the default values referenced in
- /// and , but should always be "definite" values (not "Default")
- ///
- public static readonly StronglyTypedIdConfiguration Defaults = new(
- backingType: StronglyTypedIdBackingType.Guid,
- converters: StronglyTypedIdConverter.TypeConverter | StronglyTypedIdConverter.NewtonsoftJson,
- implementations: StronglyTypedIdImplementations.IEquatable | StronglyTypedIdImplementations.IComparable);
-
- ///
- /// Combines multiple values associated
- /// with a given , returning definite values.
- ///
- ///
- public static StronglyTypedIdConfiguration Combine(
- StronglyTypedIdConfiguration attributeValues,
- StronglyTypedIdConfiguration? globalValues)
- {
- var backingType = (attributeValues.BackingType, globalValues?.BackingType) switch
- {
- (StronglyTypedIdBackingType.Default, null) => Defaults.BackingType,
- (StronglyTypedIdBackingType.Default, StronglyTypedIdBackingType.Default) => Defaults.BackingType,
- (StronglyTypedIdBackingType.Default, var globalDefault) => globalDefault.Value,
- (var specificValue, _) => specificValue
- };
-
- var converter = (attributeValues.Converters, globalValues?.Converters) switch
- {
- (StronglyTypedIdConverter.Default, null) => Defaults.Converters,
- (StronglyTypedIdConverter.Default, StronglyTypedIdConverter.Default) => Defaults.Converters,
- (StronglyTypedIdConverter.Default, var globalDefault) => globalDefault.Value,
- (var specificValue, _) => specificValue
- };
-
- var implementations = (attributeValues.Implementations, globalValues?.Implementations) switch
- {
- (StronglyTypedIdImplementations.Default, null) => Defaults.Implementations,
- (StronglyTypedIdImplementations.Default, StronglyTypedIdImplementations.Default) => Defaults.Implementations,
- (StronglyTypedIdImplementations.Default, var globalDefault) => globalDefault.Value,
- (var specificValue, _) => specificValue
- };
-
- return new StronglyTypedIdConfiguration(backingType, converter, implementations);
- }
- }
-}
\ No newline at end of file
diff --git a/src/StronglyTypedIds/StronglyTypedIdConverterExtensions.cs b/src/StronglyTypedIds/StronglyTypedIdConverterExtensions.cs
deleted file mode 100644
index 63d4174b2..000000000
--- a/src/StronglyTypedIds/StronglyTypedIdConverterExtensions.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using System;
-using System.Linq;
-
-namespace StronglyTypedIds
-{
- internal static class StronglyTypedIdConverterExtensions
- {
- private static readonly int _maxConverterId = Enum.GetValues(typeof(StronglyTypedIdConverter)).Cast().Max() * 2;
- private static readonly int _maxImplementationsId = Enum.GetValues(typeof(StronglyTypedIdImplementations)).Cast().Max() * 2;
-
- public static bool IsSet(this StronglyTypedIdConverter value, StronglyTypedIdConverter flag)
- => (value & flag) == flag;
-
- public static bool IsValidFlags(this StronglyTypedIdConverter value)
- {
- return (int)value >= 0 && (int)value < _maxConverterId;
- }
-
- public static bool IsSet(this StronglyTypedIdImplementations value, StronglyTypedIdImplementations flag)
- => (value & flag) == flag;
-
- public static bool IsValidFlags(this StronglyTypedIdImplementations value)
- {
- return (int)value >= 0 && (int)value < _maxImplementationsId;
- }
- }
-}
\ No newline at end of file
diff --git a/src/StronglyTypedIds/StronglyTypedIdGenerator.cs b/src/StronglyTypedIds/StronglyTypedIdGenerator.cs
index 6a299ad78..4bb290537 100644
--- a/src/StronglyTypedIds/StronglyTypedIdGenerator.cs
+++ b/src/StronglyTypedIds/StronglyTypedIdGenerator.cs
@@ -1,9 +1,14 @@
-using System.Collections.Generic;
+using System;
using System.Collections.Immutable;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using System.Linq;
using System.Text;
+using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
+using StronglyTypedIds.Diagnostics;
namespace StronglyTypedIds
{
@@ -11,6 +16,8 @@ namespace StronglyTypedIds
[Generator]
public class StronglyTypedIdGenerator : IIncrementalGenerator
{
+ const string TemplateSuffix = ".typedid";
+
///
public void Initialize(IncrementalGeneratorInitializationContext context)
{
@@ -19,71 +26,284 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
{
i.AddSource("StronglyTypedIdAttribute.g.cs", EmbeddedSources.StronglyTypedIdAttributeSource);
i.AddSource("StronglyTypedIdDefaultsAttribute.g.cs", EmbeddedSources.StronglyTypedIdDefaultsAttributeSource);
- i.AddSource("StronglyTypedIdBackingType.g.cs", EmbeddedSources.StronglyTypedIdBackingTypeSource);
- i.AddSource("StronglyTypedIdConverter.g.cs", EmbeddedSources.StronglyTypedIdConverterSource);
- i.AddSource("StronglyTypedIdImplementations.g.cs", EmbeddedSources.StronglyTypedIdImplementationsSource);
+ i.AddSource("Template.g.cs", EmbeddedSources.TemplateSource);
});
- IncrementalValuesProvider structDeclarations = context.SyntaxProvider
- .CreateSyntaxProvider(
- predicate: static (s, _) => Parser.IsStructTargetForGeneration(s),
- transform: static (ctx, _) => Parser.GetStructSemanticTargetForGeneration(ctx))
- .Where(static m => m is not null)!;
+ IncrementalValuesProvider<(string Path, string Name, string? Content)> allTemplates = context.AdditionalTextsProvider
+ .Where(template => Path.GetExtension(template.Path).Equals(TemplateSuffix, StringComparison.OrdinalIgnoreCase))
+ .Select((template, ct) => (
+ Path: template.Path,
+ Name: Path.GetFileNameWithoutExtension(template.Path),
+ Content: template.GetText(ct)?.ToString()));
- IncrementalValuesProvider defaultAttributesDeclarations = context.SyntaxProvider
- .CreateSyntaxProvider(
- predicate: static (s, _) => Parser.IsAttributeTargetForGeneration(s),
- transform: static (ctx, _) => Parser.GetAssemblyAttributeSemanticTargetForGeneration(ctx))
- .Where(static m => m is not null)!;
+ var templates = allTemplates
+ .Where(template => !string.IsNullOrWhiteSpace(template.Name) && template.Content is not null)
+ .Collect();
+
+ IncrementalValuesProvider> structAndDiagnostics = context.SyntaxProvider
+ .ForAttributeWithMetadataName(
+ Parser.StronglyTypedIdAttribute,
+ predicate: (node, _) => node is StructDeclarationSyntax,
+ transform: Parser.GetStructSemanticTarget)
+ .Where(static m => m is not null);
- IncrementalValueProvider<(ImmutableArray, ImmutableArray)> targetsAndDefaultAttributes
- = structDeclarations.Collect().Combine(defaultAttributesDeclarations.Collect());
+ IncrementalValuesProvider> defaultsAndDiagnostics = context.SyntaxProvider
+ .ForAttributeWithMetadataName(
+ Parser.StronglyTypedIdDefaultsAttribute,
+ predicate: (node, _) => node is CompilationUnitSyntax,
+ transform: Parser.GetDefaults)
+ .Where(static m => m is not null);
- IncrementalValueProvider<(Compilation Left, (ImmutableArray, ImmutableArray) Right)> compilationAndValues
- = context.CompilationProvider.Combine(targetsAndDefaultAttributes);
+ context.RegisterSourceOutput(
+ structAndDiagnostics.SelectMany((x, _) => x.Errors),
+ static (context, info) => context.ReportDiagnostic(info));
- context.RegisterSourceOutput(compilationAndValues,
- static (spc, source) => Execute(source.Item1, source.Item2.Item1, source.Item2.Item2, spc));
- }
+ context.RegisterSourceOutput(
+ defaultsAndDiagnostics.SelectMany((x, _) => x.Errors),
+ static (context, info) => context.ReportDiagnostic(info));
+
+ IncrementalValuesProvider structs = structAndDiagnostics
+ .Where(static x => x.Value.valid)
+ .Select((result, _) => result.Value.info);
+
+ IncrementalValueProvider<(EquatableArray<(string Name, string Content)> Content, bool isValid, DiagnosticInfo? Diagnostic)> defaultTemplateContent = defaultsAndDiagnostics
+ .Where(static x => x.Value.valid)
+ .Select((result, _) => result.Value.defaults)
+ .Collect()
+ .Combine(templates)
+ .Select(ProcessDefaults);
+
+ var structsWithDefaultsAndTemplates = structs
+ .Combine(templates)
+ .Combine(defaultTemplateContent);
- static void Execute(
- Compilation compilation,
- ImmutableArray structs,
- ImmutableArray defaults,
+ context.RegisterSourceOutput(structsWithDefaultsAndTemplates,
+ static (spc, source) => Execute(source.Left.Left, source.Left.Right, source.Right, spc));
+ }
+ private static void Execute(
+ StructToGenerate idToGenerate,
+ ImmutableArray<(string Path, string Name, string? Content)> templates,
+ (EquatableArray<(string Name, string Content)>, bool IsValid, DiagnosticInfo? Diagnostic) defaults,
SourceProductionContext context)
{
- if (structs.IsDefaultOrEmpty)
+ if (defaults.Diagnostic is { } diagnostic)
+ {
+ // report error with the default template
+ context.ReportDiagnostic(diagnostic);
+ }
+
+ if (!TryGetTemplateContent(idToGenerate, templates, defaults, in context, out var templateContents))
{
- // nothing to do yet
return;
}
- List<(string Name, string NameSpace, StronglyTypedIdConfiguration Config, ParentClass? Parent)> idsToGenerate =
- Parser.GetTypesToGenerate(compilation, structs, context.ReportDiagnostic, context.CancellationToken);
+ var sb = new StringBuilder();
+ foreach (var (name, content) in templateContents.Distinct())
+ {
+ var result = SourceGenerationHelper.CreateId(
+ idToGenerate.NameSpace,
+ idToGenerate.Name,
+ idToGenerate.Parent,
+ content,
+ addDefaultAttributes: string.IsNullOrEmpty(name),
+ sb);
+
+ var fileName = SourceGenerationHelper.CreateSourceName(
+ sb,
+ idToGenerate.NameSpace,
+ idToGenerate.Parent,
+ idToGenerate.Name,
+ name);
+
+ context.AddSource(fileName, SourceText.From(result, Encoding.UTF8));
+ }
+ }
+
- if (idsToGenerate.Count > 0)
+ private static (EquatableArray<(string Name, string Content)>, bool, DiagnosticInfo?) ProcessDefaults((ImmutableArray Left, ImmutableArray<(string Path, string Name, string? Content)> Right) all, CancellationToken _)
+ {
+ if (all.Left.IsDefaultOrEmpty)
{
- StronglyTypedIdConfiguration? globalDefaults = Parser.GetDefaults(defaults, compilation, context.ReportDiagnostic);
- StringBuilder sb = new StringBuilder();
- foreach (var idToGenerate in idsToGenerate)
+ // no default attributes, valid, but no content
+ return (EquatableArray<(string Name, string Content)>.Empty, true, null);
+ }
+
+ // technically we can never have more than one `Defaults` here
+ // but check for it just in case
+ if (all.Left is {IsDefaultOrEmpty: false, Length: > 1})
+ {
+ return (EquatableArray<(string Name, string Content)>.Empty, false, null);
+ }
+
+ var defaults = all.Left[0];
+ if (defaults.HasMultiple)
+ {
+ // not valid
+ return (EquatableArray<(string Name, string Content)>.Empty, false, null);
+ }
+
+ (string, string)? builtInTemplate = null;
+ if (defaults.Template is { } templateId)
+ {
+ // Explicit template
+ builtInTemplate = (string.Empty, EmbeddedSources.GetTemplate(templateId));
+ }
+
+ var templateNames = defaults.TemplateNames.GetArray();
+ if (templateNames is null or {Length: 0})
+ {
+ if (builtInTemplate.HasValue)
{
- sb.Clear();
- var values = StronglyTypedIdConfiguration.Combine(idToGenerate.Config, globalDefaults);
- var result = SourceGenerationHelper.CreateId(
- idToGenerate.NameSpace,
- idToGenerate.Name,
- idToGenerate.Parent,
- values.Converters,
- values.BackingType,
- values.Implementations,
- sb);
- var fileName = SourceGenerationHelper.CreateSourceName(
- idToGenerate.NameSpace,
- idToGenerate.Parent,
- idToGenerate.Name);
- context.AddSource(fileName, SourceText.From(result, Encoding.UTF8));
+ // valid, only built-in
+ var template = new EquatableArray<(string Name, string Content)>(new[] {builtInTemplate.Value});
+ return (template, true, (DiagnosticInfo?) null);
}
+
+ // not valid, need something
+ return (EquatableArray<(string Name, string Content)>.Empty, false, null);
}
+
+ // We have already checked for null/empty template name and flagged it as an error
+ if (!GetContent(templateNames, defaults.TemplateLocation!, builtInTemplate.HasValue, in all.Right, out var contents, out var diagnostic))
+ {
+ return (EquatableArray<(string Name, string Content)>.Empty, false, diagnostic);
+ }
+
+ if (builtInTemplate.HasValue)
+ {
+ contents[^1] = builtInTemplate.Value;
+ }
+
+ // Ok, we have all the templates
+ return (new EquatableArray<(string Name, string Content)>(contents), true, null);
+ }
+
+ private static bool TryGetTemplateContent(
+ in StructToGenerate idToGenerate,
+ in ImmutableArray<(string Path, string Name, string? Content)> templates,
+ (EquatableArray<(string Name, string Content)> Contents, bool IsValid, DiagnosticInfo? Diagnostics) defaults,
+ in SourceProductionContext context,
+ [NotNullWhen(true)] out (string Name, string Content)[]? templateContents)
+ {
+ (string, string)? builtIn = null;
+ if (idToGenerate.Template is { } templateId)
+ {
+ // built-in template specified
+ var content = EmbeddedSources.GetTemplate(templateId);
+ builtIn = (string.Empty, content);
+ }
+
+ if (idToGenerate.TemplateNames.GetArray() is {Length: > 0} templateNames)
+ {
+ // custom template specified
+ if (GetContent(
+ templateNames,
+ idToGenerate.TemplateLocation,
+ builtIn.HasValue,
+ in templates,
+ out templateContents,
+ out var diagnostic))
+ {
+ if (builtIn.HasValue)
+ {
+ templateContents[^1] = builtIn.Value;
+ }
+
+ return true;
+ }
+
+ // One of the templates wasn't found, so it must be invalid. Don't generate anything
+ if (diagnostic is { })
+ {
+ context.ReportDiagnostic(diagnostic);
+ }
+
+ templateContents = null;
+ return false;
+ }
+
+ if (builtIn.HasValue)
+ {
+ templateContents = new[] {builtIn.Value};
+ return true;
+ }
+
+ // nothing specified, use the defaults (if we have them)
+ if (defaults.IsValid)
+ {
+ if (defaults.Contents.GetArray() is {Length: > 0} allContent)
+ {
+ templateContents = allContent;
+ }
+ else
+ {
+ templateContents = new[] {(string.Empty, EmbeddedSources.GetTemplate(Template.Guid))};
+ }
+
+ return true;
+ }
+
+ // not valid
+ templateContents = null;
+ return false;
+ }
+
+ private static string GetEmptyTemplateContent(string templateName)
+ => $"// The {templateName}.typeid template was empty, you'll need to add some content";
+
+ private static bool GetContent(
+ string[] templateNames,
+ LocationInfo? location,
+ bool haveStandardTemplate,
+ in ImmutableArray<(string Path, string Name, string? Content)> templates,
+ [NotNullWhen(true)] out (string Name, string Content)[]? output,
+ out DiagnosticInfo? diagnostic)
+ {
+ // Length + 1 to optionally add the extra template
+ var totalTemplates = haveStandardTemplate ? templateNames.Length + 1 : templateNames.Length;
+ (string, string)[]? contents = null;
+ for (int i = 0; i < templateNames.Length; i++)
+ {
+ var templateName = templateNames[i];
+ if (string.IsNullOrEmpty(templateName))
+ {
+ output = null;
+ diagnostic = location is not null
+ ? InvalidTemplateNameDiagnostic.CreateInfo(location)
+ : null;
+ return false;
+ }
+
+ var foundTemplate = false;
+
+ foreach (var templateDetails in templates)
+ {
+ if (string.Equals(templateDetails.Name, templateName, StringComparison.Ordinal))
+ {
+ // This _could_ be empty, but we use it anyway (and add a comment in the template)
+ var content = templateDetails.Content ?? GetEmptyTemplateContent(templateName);
+ contents ??= new (string, string)[totalTemplates];
+ contents[i] = (templateName, content);
+ foundTemplate = true;
+ break;
+ }
+ }
+
+ if (!foundTemplate)
+ {
+ // Template name specified, but we don't have a template for it
+ // bail out early
+ output = null;
+ diagnostic = location is not null
+ ? UnknownTemplateDiagnostic.CreateInfo(location, templateName)
+ : null;
+ return false;
+ }
+ }
+
+ output = contents!; // only case this wouldn't be true is if templateNames is empty
+ diagnostic = null;
+ return true;
}
}
}
\ No newline at end of file
diff --git a/src/StronglyTypedIds/StronglyTypedIds.csproj b/src/StronglyTypedIds/StronglyTypedIds.csproj
index 64f63c39f..a61535bd3 100644
--- a/src/StronglyTypedIds/StronglyTypedIds.csproj
+++ b/src/StronglyTypedIds/StronglyTypedIds.csproj
@@ -6,17 +6,28 @@
enable
StronglyTypedId
A source generator for creating strongly-typed IDs by decorating with a [StronglyTypedId] attribute
+ latest
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
diff --git a/src/StronglyTypedIds/StructToGenerate.cs b/src/StronglyTypedIds/StructToGenerate.cs
new file mode 100644
index 000000000..2f2a666c7
--- /dev/null
+++ b/src/StronglyTypedIds/StructToGenerate.cs
@@ -0,0 +1,64 @@
+using System;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Text;
+
+namespace StronglyTypedIds;
+
+internal readonly record struct StructToGenerate
+{
+ public StructToGenerate(string name, string nameSpace, Template? template, string[]? templateNames, ParentClass? parent, LocationInfo templateLocation)
+ {
+ Name = name;
+ NameSpace = nameSpace;
+ TemplateNames = templateNames is null ? EquatableArray.Empty : new EquatableArray(templateNames);
+ Template = template;
+ Parent = parent;
+ TemplateLocation = templateLocation;
+ }
+
+ public string Name { get; }
+ public string NameSpace { get; }
+ public EquatableArray TemplateNames { get; }
+ public Template? Template { get; }
+ public ParentClass? Parent { get; }
+ public LocationInfo? TemplateLocation { get; }
+}
+
+internal sealed record Result(TValue Value, EquatableArray Errors)
+ where TValue : IEquatable?
+{
+ public static Result<(TValue, bool)> Fail()
+ => new((default!, false), EquatableArray.Empty);
+}
+
+
+internal readonly record struct Defaults
+{
+ public Defaults(Template? template, string[]? templateNames, LocationInfo location, bool hasMultiple)
+ {
+ TemplateNames = templateNames is null ? EquatableArray.Empty : new EquatableArray(templateNames);
+ HasMultiple = hasMultiple;
+ Template = template;
+ TemplateLocation = location;
+ }
+
+ public EquatableArray TemplateNames { get; }
+ public Template? Template { get; }
+ public LocationInfo? TemplateLocation { get; }
+ public bool HasMultiple { get; }
+}
+
+internal record ParentClass(string Modifiers, string Keyword, string Name, string Constraints, ParentClass? Child, bool IsGeneric);
+
+internal record LocationInfo(string FilePath, TextSpan TextSpan, LinePositionSpan LineSpan)
+{
+ public Location ToLocation()
+ => Location.Create(FilePath, TextSpan, LineSpan);
+
+ public static LocationInfo CreateFrom(SyntaxNode node)
+ {
+ var location = node.GetLocation();
+ // assuming that source tree is always non-null here... hopefully that's the case
+ return new LocationInfo(location.SourceTree!.FilePath, location.SourceSpan, location.GetLineSpan().Span);
+ }
+}
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/AutoGeneratedHeader.cs b/src/StronglyTypedIds/Templates/AutoGeneratedHeader.cs
index 76952553c..b782f6438 100644
--- a/src/StronglyTypedIds/Templates/AutoGeneratedHeader.cs
+++ b/src/StronglyTypedIds/Templates/AutoGeneratedHeader.cs
@@ -9,3 +9,4 @@
#pragma warning disable 1591 // publicly visible type or member must be documented
+#nullable enable
diff --git a/src/StronglyTypedIds/Templates/Guid/Guid_Base.cs b/src/StronglyTypedIds/Templates/Guid/Guid_Base.cs
deleted file mode 100644
index 200147a15..000000000
--- a/src/StronglyTypedIds/Templates/Guid/Guid_Base.cs
+++ /dev/null
@@ -1,24 +0,0 @@
- readonly partial struct TESTID : INTERFACES
- {
- public System.Guid Value { get; }
-
- public TESTID(System.Guid value)
- {
- Value = value;
- }
-
- public static TESTID New() => new TESTID(System.Guid.NewGuid());
- public static readonly TESTID Empty = new TESTID(System.Guid.Empty);
-
- public bool Equals(TESTID other) => this.Value.Equals(other.Value);
- public override bool Equals(object obj)
- {
- if (ReferenceEquals(null, obj)) return false;
- return obj is TESTID other && Equals(other);
- }
-
- public override int GetHashCode() => Value.GetHashCode();
-
- public override string ToString() => Value.ToString();
- public static bool operator ==(TESTID a, TESTID b) => a.Equals(b);
- public static bool operator !=(TESTID a, TESTID b) => !(a == b);
diff --git a/src/StronglyTypedIds/Templates/Guid/Guid_DapperTypeHandler.cs b/src/StronglyTypedIds/Templates/Guid/Guid_DapperTypeHandler.cs
deleted file mode 100644
index 7d94a235e..000000000
--- a/src/StronglyTypedIds/Templates/Guid/Guid_DapperTypeHandler.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-
- public class DapperTypeHandler : Dapper.SqlMapper.TypeHandler
- {
- public override void SetValue(System.Data.IDbDataParameter parameter, TESTID value)
- {
- parameter.Value = value.Value;
- }
-
- public override TESTID Parse(object value)
- {
- return value switch
- {
- System.Guid guidValue => new TESTID(guidValue),
- string stringValue when !string.IsNullOrEmpty(stringValue) && System.Guid.TryParse(stringValue, out var result) => new TESTID(result),
- _ => throw new System.InvalidCastException($"Unable to cast object of type {value.GetType()} to TESTID"),
- };
- }
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/Guid/Guid_EfCoreValueConverter.cs b/src/StronglyTypedIds/Templates/Guid/Guid_EfCoreValueConverter.cs
deleted file mode 100644
index 18e4d5d61..000000000
--- a/src/StronglyTypedIds/Templates/Guid/Guid_EfCoreValueConverter.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-
- public class EfCoreValueConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter
- {
- public EfCoreValueConverter() : this(null) { }
- public EfCoreValueConverter(Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints mappingHints = null)
- : base(
- id => id.Value,
- value => new TESTID(value),
- mappingHints
- ) { }
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/Guid/Guid_IComparable.cs b/src/StronglyTypedIds/Templates/Guid/Guid_IComparable.cs
deleted file mode 100644
index e0696ee2a..000000000
--- a/src/StronglyTypedIds/Templates/Guid/Guid_IComparable.cs
+++ /dev/null
@@ -1 +0,0 @@
- public int CompareTo(TESTID other) => Value.CompareTo(other.Value);
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/Guid/Guid_NewtonsoftJsonConverter.cs b/src/StronglyTypedIds/Templates/Guid/Guid_NewtonsoftJsonConverter.cs
deleted file mode 100644
index 9b96b63b2..000000000
--- a/src/StronglyTypedIds/Templates/Guid/Guid_NewtonsoftJsonConverter.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-
- class TESTIDNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter
- {
- public override bool CanConvert(System.Type objectType)
- {
- return objectType == typeof(TESTID);
- }
-
- public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
- {
- var id = (TESTID)value;
- serializer.Serialize(writer, id.Value);
- }
-
- public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
- {
- var guid = serializer.Deserialize(reader);
- return guid.HasValue ? new TESTID(guid.Value) : null;
- }
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/Guid/Guid_SystemTextJsonConverter.cs b/src/StronglyTypedIds/Templates/Guid/Guid_SystemTextJsonConverter.cs
deleted file mode 100644
index 4dc733db9..000000000
--- a/src/StronglyTypedIds/Templates/Guid/Guid_SystemTextJsonConverter.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-
- class TESTIDSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter
- {
- public override TESTID Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options)
- {
- return new TESTID(System.Guid.Parse(reader.GetString()));
- }
-
- public override void Write(System.Text.Json.Utf8JsonWriter writer, TESTID value, System.Text.Json.JsonSerializerOptions options)
- {
- writer.WriteStringValue(value.Value);
- }
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/Guid/Guid_TypeConverter.cs b/src/StronglyTypedIds/Templates/Guid/Guid_TypeConverter.cs
deleted file mode 100644
index 6ae7eb06b..000000000
--- a/src/StronglyTypedIds/Templates/Guid/Guid_TypeConverter.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-
- class TESTIDTypeConverter : System.ComponentModel.TypeConverter
- {
- public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType)
- {
- return sourceType == typeof(System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
- }
-
- public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
- {
- return value switch
- {
- System.Guid guidValue => new TESTID(guidValue),
- string stringValue when !string.IsNullOrEmpty(stringValue) && System.Guid.TryParse(stringValue, out var result) => new TESTID(result),
- _ => base.ConvertFrom(context, culture, value),
- };
- }
-
- public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType)
- {
- return sourceType == typeof(System.Guid) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType);
- }
-
- public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, System.Type destinationType)
- {
- if (value is TESTID idValue)
- {
- if (destinationType == typeof(System.Guid))
- {
- return idValue.Value;
- }
-
- if (destinationType == typeof(string))
- {
- return idValue.Value.ToString();
- }
- }
-
- return base.ConvertTo(context, culture, value, destinationType);
- }
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/Int/Int_Base.cs b/src/StronglyTypedIds/Templates/Int/Int_Base.cs
deleted file mode 100644
index 08ce1fca6..000000000
--- a/src/StronglyTypedIds/Templates/Int/Int_Base.cs
+++ /dev/null
@@ -1,23 +0,0 @@
- readonly partial struct TESTID : INTERFACES
- {
- public int Value { get; }
-
- public TESTID(int value)
- {
- Value = value;
- }
-
- public static readonly TESTID Empty = new TESTID(0);
-
- public bool Equals(TESTID other) => this.Value.Equals(other.Value);
- public override bool Equals(object obj)
- {
- if (ReferenceEquals(null, obj)) return false;
- return obj is TESTID other && Equals(other);
- }
-
- public override int GetHashCode() => Value.GetHashCode();
-
- public override string ToString() => Value.ToString();
- public static bool operator ==(TESTID a, TESTID b) => a.Equals(b);
- public static bool operator !=(TESTID a, TESTID b) => !(a == b);
diff --git a/src/StronglyTypedIds/Templates/Int/Int_DapperTypeHandler.cs b/src/StronglyTypedIds/Templates/Int/Int_DapperTypeHandler.cs
deleted file mode 100644
index 8e3dc42c9..000000000
--- a/src/StronglyTypedIds/Templates/Int/Int_DapperTypeHandler.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-
- public class DapperTypeHandler : Dapper.SqlMapper.TypeHandler
- {
- public override void SetValue(System.Data.IDbDataParameter parameter, TESTID value)
- {
- parameter.Value = value.Value;
- }
-
- public override TESTID Parse(object value)
- {
- return value switch
- {
- int intValue => new TESTID(intValue),
- long longValue when longValue < int.MaxValue => new TESTID((int)longValue),
- string stringValue when !string.IsNullOrEmpty(stringValue) && int.TryParse(stringValue, out var result) => new TESTID(result),
- _ => throw new System.InvalidCastException($"Unable to cast object of type {value.GetType()} to TESTID"),
- };
- }
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/Int/Int_EfCoreValueConverter.cs b/src/StronglyTypedIds/Templates/Int/Int_EfCoreValueConverter.cs
deleted file mode 100644
index 2245e6cf1..000000000
--- a/src/StronglyTypedIds/Templates/Int/Int_EfCoreValueConverter.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-
- public class EfCoreValueConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter
- {
- public EfCoreValueConverter() : this(null) { }
- public EfCoreValueConverter(Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints mappingHints = null)
- : base(
- id => id.Value,
- value => new TESTID(value),
- mappingHints
- ) { }
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/Int/Int_IComparable.cs b/src/StronglyTypedIds/Templates/Int/Int_IComparable.cs
deleted file mode 100644
index e0696ee2a..000000000
--- a/src/StronglyTypedIds/Templates/Int/Int_IComparable.cs
+++ /dev/null
@@ -1 +0,0 @@
- public int CompareTo(TESTID other) => Value.CompareTo(other.Value);
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/Int/Int_NewtonsoftJsonConverter.cs b/src/StronglyTypedIds/Templates/Int/Int_NewtonsoftJsonConverter.cs
deleted file mode 100644
index 56409d73b..000000000
--- a/src/StronglyTypedIds/Templates/Int/Int_NewtonsoftJsonConverter.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-
- class TESTIDNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter
- {
- public override bool CanConvert(System.Type objectType)
- {
- return objectType == typeof(TESTID);
- }
-
- public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
- {
- var id = (TESTID)value;
- serializer.Serialize(writer, id.Value);
- }
-
- public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
- {
- var result = serializer.Deserialize(reader);
- return result.HasValue ? new TESTID(result.Value) : null;
- }
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/Int/Int_SystemTextJsonConverter.cs b/src/StronglyTypedIds/Templates/Int/Int_SystemTextJsonConverter.cs
deleted file mode 100644
index e388d1e8e..000000000
--- a/src/StronglyTypedIds/Templates/Int/Int_SystemTextJsonConverter.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-
- class TESTIDSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter
- {
- public override TESTID Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options)
- {
- return new TESTID(reader.GetInt32());
- }
-
- public override void Write(System.Text.Json.Utf8JsonWriter writer, TESTID value, System.Text.Json.JsonSerializerOptions options)
- {
- writer.WriteNumberValue(value.Value);
- }
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/Int/Int_TypeConverter.cs b/src/StronglyTypedIds/Templates/Int/Int_TypeConverter.cs
deleted file mode 100644
index 23cc26327..000000000
--- a/src/StronglyTypedIds/Templates/Int/Int_TypeConverter.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-
- class TESTIDTypeConverter : System.ComponentModel.TypeConverter
- {
- public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType)
- {
- return sourceType == typeof(int) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
- }
-
- public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
- {
- return value switch
- {
- int intValue => new TESTID(intValue),
- string stringValue when !string.IsNullOrEmpty(stringValue) && int.TryParse(stringValue, out var result) => new TESTID(result),
- _ => base.ConvertFrom(context, culture, value),
- };
- }
-
- public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType)
- {
- return sourceType == typeof(int) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType);
- }
-
- public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, System.Type destinationType)
- {
- if (value is TESTID idValue)
- {
- if (destinationType == typeof(int))
- {
- return idValue.Value;
- }
-
- if (destinationType == typeof(string))
- {
- return idValue.Value.ToString();
- }
- }
-
- return base.ConvertTo(context, culture, value, destinationType);
- }
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/Long/Long_Base.cs b/src/StronglyTypedIds/Templates/Long/Long_Base.cs
deleted file mode 100644
index 38d9fc5a6..000000000
--- a/src/StronglyTypedIds/Templates/Long/Long_Base.cs
+++ /dev/null
@@ -1,23 +0,0 @@
- readonly partial struct TESTID : INTERFACES
- {
- public long Value { get; }
-
- public TESTID(long value)
- {
- Value = value;
- }
-
- public static readonly TESTID Empty = new TESTID(0);
-
- public bool Equals(TESTID other) => this.Value.Equals(other.Value);
- public override bool Equals(object obj)
- {
- if (ReferenceEquals(null, obj)) return false;
- return obj is TESTID other && Equals(other);
- }
-
- public override int GetHashCode() => Value.GetHashCode();
-
- public override string ToString() => Value.ToString();
- public static bool operator ==(TESTID a, TESTID b) => a.Equals(b);
- public static bool operator !=(TESTID a, TESTID b) => !(a == b);
diff --git a/src/StronglyTypedIds/Templates/Long/Long_DapperTypeHandler.cs b/src/StronglyTypedIds/Templates/Long/Long_DapperTypeHandler.cs
deleted file mode 100644
index 42dac85c9..000000000
--- a/src/StronglyTypedIds/Templates/Long/Long_DapperTypeHandler.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-
- public class DapperTypeHandler : Dapper.SqlMapper.TypeHandler
- {
- public override void SetValue(System.Data.IDbDataParameter parameter, TESTID value)
- {
- parameter.Value = value.Value;
- }
-
- public override TESTID Parse(object value)
- {
- return value switch
- {
- long longValue => new TESTID(longValue),
- int intValue => new TESTID(intValue),
- short shortValue => new TESTID(shortValue),
- string stringValue when !string.IsNullOrEmpty(stringValue) && long.TryParse(stringValue, out var result) => new TESTID(result),
- _ => throw new System.InvalidCastException($"Unable to cast object of type {value.GetType()} to TESTID"),
- };
- }
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/Long/Long_EfCoreValueConverter.cs b/src/StronglyTypedIds/Templates/Long/Long_EfCoreValueConverter.cs
deleted file mode 100644
index 96422f377..000000000
--- a/src/StronglyTypedIds/Templates/Long/Long_EfCoreValueConverter.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-
- public class EfCoreValueConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter
- {
- public EfCoreValueConverter() : this(null) { }
- public EfCoreValueConverter(Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints mappingHints = null)
- : base(
- id => id.Value,
- value => new TESTID(value),
- mappingHints
- ) { }
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/Long/Long_IComparable.cs b/src/StronglyTypedIds/Templates/Long/Long_IComparable.cs
deleted file mode 100644
index e0696ee2a..000000000
--- a/src/StronglyTypedIds/Templates/Long/Long_IComparable.cs
+++ /dev/null
@@ -1 +0,0 @@
- public int CompareTo(TESTID other) => Value.CompareTo(other.Value);
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/Long/Long_NewtonsoftJsonConverter.cs b/src/StronglyTypedIds/Templates/Long/Long_NewtonsoftJsonConverter.cs
deleted file mode 100644
index f1bcb6a98..000000000
--- a/src/StronglyTypedIds/Templates/Long/Long_NewtonsoftJsonConverter.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-
- class TESTIDNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter
- {
- public override bool CanConvert(System.Type objectType)
- {
- return objectType == typeof(TESTID);
- }
-
- public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
- {
- var id = (TESTID)value;
- serializer.Serialize(writer, id.Value);
- }
-
- public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
- {
- var result = serializer.Deserialize(reader);
- return result.HasValue ? new TESTID(result.Value) : null;
- }
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/Long/Long_SystemTextJsonConverter.cs b/src/StronglyTypedIds/Templates/Long/Long_SystemTextJsonConverter.cs
deleted file mode 100644
index 5cf5825eb..000000000
--- a/src/StronglyTypedIds/Templates/Long/Long_SystemTextJsonConverter.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-
- class TESTIDSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter
- {
- public override TESTID Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options)
- {
- return new TESTID(reader.GetInt64());
- }
-
- public override void Write(System.Text.Json.Utf8JsonWriter writer, TESTID value, System.Text.Json.JsonSerializerOptions options)
- {
- writer.WriteNumberValue(value.Value);
- }
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/Long/Long_TypeConverter.cs b/src/StronglyTypedIds/Templates/Long/Long_TypeConverter.cs
deleted file mode 100644
index 4785b648f..000000000
--- a/src/StronglyTypedIds/Templates/Long/Long_TypeConverter.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-
- class TESTIDTypeConverter : System.ComponentModel.TypeConverter
- {
- public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType)
- {
- return sourceType == typeof(long) || sourceType == typeof(int) || sourceType == typeof(short) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
- }
-
- public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
- {
- return value switch
- {
- long longValue => new TESTID(longValue),
- int intValue => new TESTID(intValue),
- short shortValue => new TESTID(shortValue),
- string stringValue when !string.IsNullOrEmpty(stringValue) && long.TryParse(stringValue, out var result) => new TESTID(result),
- _ => base.ConvertFrom(context, culture, value),
- };
- }
-
- public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType)
- {
- return sourceType == typeof(long) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType);
- }
-
- public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, System.Type destinationType)
- {
- if (value is TESTID idValue)
- {
- if (destinationType == typeof(long))
- {
- return idValue.Value;
- }
-
- if (destinationType == typeof(string))
- {
- return idValue.Value.ToString();
- }
- }
-
- return base.ConvertTo(context, culture, value, destinationType);
- }
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/NewId/NewId_Base.cs b/src/StronglyTypedIds/Templates/NewId/NewId_Base.cs
deleted file mode 100644
index 854cd477a..000000000
--- a/src/StronglyTypedIds/Templates/NewId/NewId_Base.cs
+++ /dev/null
@@ -1,24 +0,0 @@
- readonly partial struct TESTID : INTERFACES
- {
- public MassTransit.NewId Value { get; }
-
- public TESTID(MassTransit.NewId value)
- {
- Value = value;
- }
-
- public static TESTID New() => new TESTID(MassTransit.NewId.Next());
- public static readonly TESTID Empty = new TESTID(MassTransit.NewId.Empty);
-
- public bool Equals(TESTID other) => this.Value.Equals(other.Value);
- public override bool Equals(object obj)
- {
- if (ReferenceEquals(null, obj)) return false;
- return obj is TESTID other && Equals(other);
- }
-
- public override int GetHashCode() => Value.GetHashCode();
-
- public override string ToString() => Value.ToString();
- public static bool operator ==(TESTID a, TESTID b) => a.Equals(b);
- public static bool operator !=(TESTID a, TESTID b) => !(a == b);
diff --git a/src/StronglyTypedIds/Templates/NewId/NewId_DapperTypeHandler.cs b/src/StronglyTypedIds/Templates/NewId/NewId_DapperTypeHandler.cs
deleted file mode 100644
index 8d4af7b02..000000000
--- a/src/StronglyTypedIds/Templates/NewId/NewId_DapperTypeHandler.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-
- public class DapperTypeHandler : Dapper.SqlMapper.TypeHandler
- {
- public override void SetValue(System.Data.IDbDataParameter parameter, TESTID value)
- {
- parameter.Value = value.Value.ToGuid();
- }
-
- public override TESTID Parse(object value)
- {
- return value switch
- {
- System.Guid guidValue => new TESTID(MassTransit.NewId.FromGuid(guidValue)),
- string stringValue when !string.IsNullOrEmpty(stringValue) && System.Guid.TryParse(stringValue, out var result) => new TESTID(MassTransit.NewId.FromGuid(result)),
- _ => throw new System.InvalidCastException($"Unable to cast object of type {value.GetType()} to TESTID"),
- };
- }
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/NewId/NewId_EfCoreValueConverter.cs b/src/StronglyTypedIds/Templates/NewId/NewId_EfCoreValueConverter.cs
deleted file mode 100644
index 6b838a340..000000000
--- a/src/StronglyTypedIds/Templates/NewId/NewId_EfCoreValueConverter.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-
- public class EfCoreValueConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter
- {
- public EfCoreValueConverter() : this(null) { }
- public EfCoreValueConverter(Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints mappingHints = null)
- : base(
- id => id.Value.ToGuid(),
- value => new TESTID(MassTransit.NewId.FromGuid(value)),
- mappingHints
- ) { }
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/NewId/NewId_IComparable.cs b/src/StronglyTypedIds/Templates/NewId/NewId_IComparable.cs
deleted file mode 100644
index e0696ee2a..000000000
--- a/src/StronglyTypedIds/Templates/NewId/NewId_IComparable.cs
+++ /dev/null
@@ -1 +0,0 @@
- public int CompareTo(TESTID other) => Value.CompareTo(other.Value);
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/NewId/NewId_NewtonsoftJsonConverter.cs b/src/StronglyTypedIds/Templates/NewId/NewId_NewtonsoftJsonConverter.cs
deleted file mode 100644
index f3e02dafc..000000000
--- a/src/StronglyTypedIds/Templates/NewId/NewId_NewtonsoftJsonConverter.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-
- class TESTIDNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter
- {
- public override bool CanConvert(System.Type objectType)
- {
- return objectType == typeof(TESTID);
- }
-
- public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
- {
- var id = (TESTID)value;
- serializer.Serialize(writer, id.Value.ToGuid());
- }
-
- public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
- {
- var guid = serializer.Deserialize(reader);
- return guid.HasValue ? new TESTID(MassTransit.NewId.FromGuid(guid.Value)) : null;
- }
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/NewId/NewId_SystemTextJsonConverter.cs b/src/StronglyTypedIds/Templates/NewId/NewId_SystemTextJsonConverter.cs
deleted file mode 100644
index 082fef2ba..000000000
--- a/src/StronglyTypedIds/Templates/NewId/NewId_SystemTextJsonConverter.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-
- class TESTIDSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter
- {
- public override TESTID Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options)
- {
- return new TESTID(MassTransit.NewId.FromGuid(reader.GetGuid()));
- }
-
- public override void Write(System.Text.Json.Utf8JsonWriter writer, TESTID value, System.Text.Json.JsonSerializerOptions options)
- {
- writer.WriteStringValue(value.Value.ToGuid());
- }
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/NewId/NewId_TypeConverter.cs b/src/StronglyTypedIds/Templates/NewId/NewId_TypeConverter.cs
deleted file mode 100644
index f923c90ab..000000000
--- a/src/StronglyTypedIds/Templates/NewId/NewId_TypeConverter.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-
- class TESTIDTypeConverter : System.ComponentModel.TypeConverter
- {
- public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType)
- {
- return sourceType == typeof(System.Guid) || sourceType == typeof(MassTransit.NewId) ||
- sourceType == typeof(string) || base.CanConvertFrom
- (context, sourceType);
- }
-
- public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
- {
- return value switch
- {
- MassTransit.NewId newIdValue => new TESTID(newIdValue),
- System.Guid guidValue => new TESTID(MassTransit.NewId.FromGuid(guidValue)),
- string stringValue when !string.IsNullOrEmpty(stringValue) && System.Guid.TryParse(stringValue, out var result) => new TESTID(MassTransit.NewId.FromGuid(result)),
- _ => base.ConvertFrom(context, culture, value),
- };
- }
-
- public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType)
- {
- return sourceType == typeof(System.Guid) || sourceType == typeof(MassTransit.NewId) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType);
- }
-
- public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, System.Type destinationType)
- {
- if (value is TESTID idValue)
- {
- if (destinationType == typeof(MassTransit.NewId))
- {
- return idValue.Value;
- }
-
- if (destinationType == typeof(System.Guid))
- {
- return idValue.Value.ToGuid();
- }
-
- if (destinationType == typeof(string))
- {
- return idValue.Value.ToGuid().ToString();
- }
- }
-
- return base.ConvertTo(context, culture, value, destinationType);
- }
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/NullableString/NullableString_Base.cs b/src/StronglyTypedIds/Templates/NullableString/NullableString_Base.cs
deleted file mode 100644
index 94a6eaffb..000000000
--- a/src/StronglyTypedIds/Templates/NullableString/NullableString_Base.cs
+++ /dev/null
@@ -1,31 +0,0 @@
- readonly partial struct TESTID : INTERFACES
- {
- public string? Value { get; }
-
- public TESTID(string? value)
- {
- Value = value;
- }
-
- public static readonly TESTID Empty = new TESTID(string.Empty);
-
- public bool Equals(TESTID other)
- {
- return (Value, other.Value) switch
- {
- (null, null) => true,
- (null, _) => false,
- (_, null) => false,
- (_, _) => Value.Equals(other.Value),
- };
- }
- public override bool Equals(object? obj)
- {
- if (ReferenceEquals(null, obj)) return false;
- return obj is TESTID other && Equals(other);
- }
-
- public override int GetHashCode() => Value?.GetHashCode() ?? 0;
- public override string? ToString() => Value;
- public static bool operator ==(TESTID a, TESTID b) => a.Equals(b);
- public static bool operator !=(TESTID a, TESTID b) => !(a == b);
diff --git a/src/StronglyTypedIds/Templates/NullableString/NullableString_DapperTypeHandler.cs b/src/StronglyTypedIds/Templates/NullableString/NullableString_DapperTypeHandler.cs
deleted file mode 100644
index 1524a13b1..000000000
--- a/src/StronglyTypedIds/Templates/NullableString/NullableString_DapperTypeHandler.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-
- public class DapperTypeHandler : Dapper.SqlMapper.TypeHandler
- {
- public override void SetValue(System.Data.IDbDataParameter parameter, TESTID value)
- {
- parameter.Value = value.Value;
- }
-
- public override TESTID Parse(object value)
- {
- return value switch
- {
- null => new TESTID(null),
- System.DBNull => new TESTID(null),
- string stringValue => new TESTID(stringValue),
- _ => throw new System.InvalidCastException($"Unable to cast object of type {value.GetType()} to TESTID"),
- };
- }
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/NullableString/NullableString_EfCoreValueConverter.cs b/src/StronglyTypedIds/Templates/NullableString/NullableString_EfCoreValueConverter.cs
deleted file mode 100644
index 443ad1aa0..000000000
--- a/src/StronglyTypedIds/Templates/NullableString/NullableString_EfCoreValueConverter.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-
- public class EfCoreValueConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter
- {
- public EfCoreValueConverter() : this(null) { }
- public EfCoreValueConverter(Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null)
- : base(
- id => id.Value!,
- value => new TESTID(value),
- mappingHints
- ) { }
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/NullableString/NullableString_IComparable.cs b/src/StronglyTypedIds/Templates/NullableString/NullableString_IComparable.cs
deleted file mode 100644
index 5cdc51ac9..000000000
--- a/src/StronglyTypedIds/Templates/NullableString/NullableString_IComparable.cs
+++ /dev/null
@@ -1,10 +0,0 @@
- public int CompareTo(TESTID other)
- {
- return (Value, other.Value) switch
- {
- (null, null) => 0,
- (null, _) => -1,
- (_, null) => 1,
- (_, _) => Value.CompareTo(other.Value),
- };
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/NullableString/NullableString_NewtonsoftJsonConverter.cs b/src/StronglyTypedIds/Templates/NullableString/NullableString_NewtonsoftJsonConverter.cs
deleted file mode 100644
index 9d536aa49..000000000
--- a/src/StronglyTypedIds/Templates/NullableString/NullableString_NewtonsoftJsonConverter.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-
- class TESTIDNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter
- {
- public override bool CanConvert(System.Type objectType)
- {
- return objectType == typeof(TESTID);
- }
-
- public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object? value, Newtonsoft.Json.JsonSerializer serializer)
- {
- if (value is null)
- {
- serializer.Serialize(writer, null);
- }
- else
- {
- var id = (TESTID)value;
- serializer.Serialize(writer, id.Value);
- }
- }
-
- public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object? existingValue, Newtonsoft.Json.JsonSerializer serializer)
- {
- return new TESTID(serializer.Deserialize(reader));
- }
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/NullableString/NullableString_SystemTextJsonConverter.cs b/src/StronglyTypedIds/Templates/NullableString/NullableString_SystemTextJsonConverter.cs
deleted file mode 100644
index 9f2f7cf1e..000000000
--- a/src/StronglyTypedIds/Templates/NullableString/NullableString_SystemTextJsonConverter.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-
- class TESTIDSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter
- {
- public override TESTID Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options)
- {
- return new TESTID(reader.GetString());
- }
-
- public override void Write(System.Text.Json.Utf8JsonWriter writer, TESTID value, System.Text.Json.JsonSerializerOptions options)
- {
- if (value.Value is null)
- {
- writer.WriteNullValue();
- }
- else
- {
- writer.WriteStringValue(value.Value);
- }
- }
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/NullableString/NullableString_TypeConverter.cs b/src/StronglyTypedIds/Templates/NullableString/NullableString_TypeConverter.cs
deleted file mode 100644
index b0f90cc19..000000000
--- a/src/StronglyTypedIds/Templates/NullableString/NullableString_TypeConverter.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-
- class TESTIDTypeConverter : System.ComponentModel.TypeConverter
- {
- public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext? context, System.Type sourceType)
- {
- return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
- }
-
- public override object? ConvertFrom(System.ComponentModel.ITypeDescriptorContext? context, System.Globalization.CultureInfo? culture, object value)
- {
- if (value is null)
- {
- return new TESTID(null);
- }
-
- var stringValue = value as string;
- if (stringValue is not null)
- {
- return new TESTID(stringValue);
- }
-
- return base.ConvertFrom(context, culture, value);
- }
-
- public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext? context, System.Type? sourceType)
- {
- return sourceType == typeof(string) || base.CanConvertTo(context, sourceType);
- }
-
- public override object? ConvertTo(System.ComponentModel.ITypeDescriptorContext? context, System.Globalization.CultureInfo? culture, object? value, System.Type destinationType)
- {
- if (value is TESTID idValue)
- {
- if (destinationType == typeof(string))
- {
- return idValue.Value;
- }
- }
-
- return base.ConvertTo(context, culture, value, destinationType);
- }
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/String/String_Base.cs b/src/StronglyTypedIds/Templates/String/String_Base.cs
deleted file mode 100644
index 023df780b..000000000
--- a/src/StronglyTypedIds/Templates/String/String_Base.cs
+++ /dev/null
@@ -1,32 +0,0 @@
- readonly partial struct TESTID : INTERFACES
- {
- public string Value { get; }
-
- public TESTID(string value)
- {
- Value = value ?? throw new System.ArgumentNullException(nameof(value));
- }
-
- public static readonly TESTID Empty = new TESTID(string.Empty);
-
- public bool Equals(TESTID other)
- {
- return (Value, other.Value) switch
- {
- (null, null) => true,
- (null, _) => false,
- (_, null) => false,
- (_, _) => Value.Equals(other.Value),
- };
- }
- public override bool Equals(object obj)
- {
- if (ReferenceEquals(null, obj)) return false;
- return obj is TESTID other && Equals(other);
- }
-
- public override int GetHashCode() => Value.GetHashCode();
-
- public override string ToString() => Value;
- public static bool operator ==(TESTID a, TESTID b) => a.Equals(b);
- public static bool operator !=(TESTID a, TESTID b) => !(a == b);
diff --git a/src/StronglyTypedIds/Templates/String/String_DapperTypeHandler.cs b/src/StronglyTypedIds/Templates/String/String_DapperTypeHandler.cs
deleted file mode 100644
index 93d6ff7bf..000000000
--- a/src/StronglyTypedIds/Templates/String/String_DapperTypeHandler.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-
- public class DapperTypeHandler : Dapper.SqlMapper.TypeHandler
- {
- public override void SetValue(System.Data.IDbDataParameter parameter, TESTID value)
- {
- parameter.Value = value.Value;
- }
-
- public override TESTID Parse(object value)
- {
- return value switch
- {
- string stringValue => new TESTID(stringValue),
- _ => throw new System.InvalidCastException($"Unable to cast object of type {value.GetType()} to TESTID"),
- };
- }
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/String/String_EfCoreValueConverter.cs b/src/StronglyTypedIds/Templates/String/String_EfCoreValueConverter.cs
deleted file mode 100644
index 76a2b7a63..000000000
--- a/src/StronglyTypedIds/Templates/String/String_EfCoreValueConverter.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-
- public class EfCoreValueConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter
- {
- public EfCoreValueConverter() : this(null) { }
- public EfCoreValueConverter(Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints mappingHints = null)
- : base(
- id => id.Value,
- value => new TESTID(value),
- mappingHints
- ) { }
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/String/String_IComparable.cs b/src/StronglyTypedIds/Templates/String/String_IComparable.cs
deleted file mode 100644
index 5cdc51ac9..000000000
--- a/src/StronglyTypedIds/Templates/String/String_IComparable.cs
+++ /dev/null
@@ -1,10 +0,0 @@
- public int CompareTo(TESTID other)
- {
- return (Value, other.Value) switch
- {
- (null, null) => 0,
- (null, _) => -1,
- (_, null) => 1,
- (_, _) => Value.CompareTo(other.Value),
- };
- }
\ No newline at end of file
diff --git a/src/StronglyTypedIds/Templates/String/String_NewtonsoftJsonConverter.cs b/src/StronglyTypedIds/Templates/String/String_NewtonsoftJsonConverter.cs
deleted file mode 100644
index e331c4bdc..000000000
--- a/src/StronglyTypedIds/Templates/String/String_NewtonsoftJsonConverter.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-
- class TESTIDNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter
- {
- public override bool CanConvert(System.Type objectType)
- {
- return objectType == typeof(TESTID);
- }
-
- public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
- {
- var id = (TESTID)value;
- serializer.Serialize(writer, id.Value);
- }
-
- public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
- {
- if (objectType == typeof(TESTID?))
- {
- var value = serializer.Deserialize