### Install and Use Community Templates Source: https://context7.com/andrewlock/stronglytypedid/llms.txt Install the community templates package to access pre-built converters for frameworks like EF Core and Dapper. ```bash dotnet add package StronglyTypedId.Templates --version 1.0.0-beta08 ``` ```csharp using StronglyTypedIds; // Full templates include: TypeConverter, System.Text.Json, Newtonsoft.Json, // EF Core ValueConverter, and Dapper TypeHandler [StronglyTypedId("guid-full")] public partial struct GuidId { } [StronglyTypedId("int-full")] public partial struct IntId { } [StronglyTypedId("long-full")] public partial struct LongId { } [StronglyTypedId("string-full")] public partial struct StringId { } [StronglyTypedId("nullablestring-full")] public partial struct NullableStringId { } // MassTransit NewId support [StronglyTypedId("newid-full")] public partial struct NewIdBasedId { } // Mix built-in template with community add-ons [StronglyTypedId(Template.Guid, "guid-efcore")] // Built-in + EF Core only [StronglyTypedId(Template.Int, "int-dapper")] // Built-in + Dapper only [StronglyTypedId(Template.Long, "long-newtonsoftjson")] // Built-in + Newtonsoft only // Available standalone templates: // - guid-dapper, guid-efcore, guid-newtonsoftjson // - int-dapper, int-efcore, int-newtonsoftjson // - long-dapper, long-efcore, long-newtonsoftjson // - string-dapper, string-efcore, string-newtonsoftjson ``` -------------------------------- ### Install StronglyTypedId via CLI Source: https://github.com/andrewlock/stronglytypedid/blob/master/README.md Use the dotnet CLI to add the NuGet package to your project. ```bash dotnet add package StronglyTypedId --version 1.0.0-beta08 ``` -------------------------------- ### Install StronglyTypedId Package Source: https://context7.com/andrewlock/stronglytypedid/llms.txt Methods for adding the library to a .NET project via CLI or project file. ```bash dotnet add package StronglyTypedId --version 1.0.0-beta08 ``` ```xml Exe net7.0 ``` -------------------------------- ### CS0436 Warning Example Source: https://github.com/andrewlock/stronglytypedid/blob/master/README.md Example of the compiler warning generated when type conflicts occur due to internal attribute duplication. ```bash warning CS0436: The type 'StronglyTypedIdImplementations' in 'StronglyTypedIds\StronglyTypedIds.StronglyTypedIdGenerator\StronglyTypedIdImplementations.cs' conflicts with the imported type 'StronglyTypedIdImplementations' in 'MyProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. ``` -------------------------------- ### StronglyTypedId Parsing and Formatting Examples Source: https://context7.com/andrewlock/stronglytypedid/llms.txt Demonstrates basic parsing, span-based parsing, TryParse, and IFormattable formatting for strongly-typed IDs. Ensure the necessary types are defined with the [StronglyTypedId] attribute. ```csharp using StronglyTypedIds; [StronglyTypedId] public partial struct OrderId { } [StronglyTypedId(Template.Int)] public partial struct ProductId { } // Basic parsing var orderId = OrderId.Parse("550e8400-e29b-41d4-a716-446655440000"); var productId = ProductId.Parse("42"); Console.WriteLine(orderId.Value); // Output: 550e8400-e29b-41d4-a716-446655440000 Console.WriteLine(productId.Value); // Output: 42 // Span-based parsing (.NET 6+) ReadOnlySpan guidSpan = "550e8400-e29b-41d4-a716-446655440000"; var fromSpan = OrderId.Parse(guidSpan); // TryParse with provider (.NET 7+) if (OrderId.TryParse("550e8400-e29b-41d4-a716-446655440000", provider: null, out var parsed)) { Console.WriteLine($"Parsed: {parsed}"); } // IFormattable - custom format strings var id = new OrderId(Guid.Parse("550e8400-e29b-41d4-a716-446655440000")); Console.WriteLine(id.ToString("N", null)); // Output: 550e8400e29b41d4a716446655440000 Console.WriteLine(id.ToString("B", null)); // Output: {550e8400-e29b-41d4-a716-446655440000} Console.WriteLine(id.ToString("D", null)); // Output: 550e8400-e29b-41d4-a716-446655440000 // TryFormat for span-based formatting (.NET 6+) Span buffer = stackalloc char[36]; if (id.TryFormat(buffer, out int charsWritten, "D")) { Console.WriteLine(buffer[..charsWritten].ToString()); } // UTF-8 formatting (.NET 8+) Span utf8Buffer = stackalloc byte[36]; if (id.TryFormat(utf8Buffer, out int bytesWritten, "D", provider: null)) { Console.WriteLine(System.Text.Encoding.UTF8.GetString(utf8Buffer[..bytesWritten])); } // Generic parsing constraints (.NET 7+) T ParseId(string value) where T : IParsable { return T.Parse(value, null); } var genericParsed = ParseId("550e8400-e29b-41d4-a716-446655440000"); ``` -------------------------------- ### TypeConverter Implementation Source: https://github.com/andrewlock/stronglytypedid/blob/master/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateMultipleTemplatesWithBuiltIn.verified.txt Handles conversion between MyId, Guid, and string types for UI and data binding scenarios. ```APIDOC ## TypeConverter Conversion Logic ### Description Provides methods to convert MyId to and from Guid or string types, enabling compatibility with standard .NET type descriptors. ### Methods - **CanConvertFrom**: Checks if the source type (Guid or string) can be converted to MyId. - **ConvertFrom**: Performs the conversion from Guid or string to MyId. - **CanConvertTo**: Checks if MyId can be converted to the destination type (Guid or string). - **ConvertTo**: Performs the conversion from MyId to the destination type. ``` -------------------------------- ### Implement TryFormat for StronglyTypedId Source: https://github.com/andrewlock/stronglytypedid/blob/master/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateVeryNestedIdInFileScopeNamespace.verified.txt This implementation uses the StringSyntax attribute for GUID formatting and writes the value to a destination span. ```csharp [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] global::System.ReadOnlySpan format, global::System.IFormatProvider? provider) => Value.TryFormat(utf8Destination, out bytesWritten, format); #endif } } } } } ``` -------------------------------- ### Configure Backing Types with Template Enum Source: https://context7.com/andrewlock/stronglytypedid/llms.txt Specifying different primitive backing types like Guid, Int, Long, or String for the generated ID. ```csharp using StronglyTypedIds; // Guid-backed ID (default) [StronglyTypedId(Template.Guid)] public partial struct GuidId { } // Integer-backed ID [StronglyTypedId(Template.Int)] public partial struct IntId { } // Long-backed ID [StronglyTypedId(Template.Long)] public partial struct LongId { } // String-backed ID [StronglyTypedId(Template.String)] public partial struct StringId { } // Usage examples var guidId = GuidId.New(); Console.WriteLine(guidId.Value); // Output: 3fa85f64-5717-4562-b3fc-2c963f66afa6 var intId = new IntId(42); Console.WriteLine(intId.Value); // Output: 42 Console.WriteLine(IntId.Empty.Value); // Output: 0 var longId = new LongId(9223372036854775807); Console.WriteLine(longId.Value); // Output: 9223372036854775807 var stringId = new StringId("user-123"); Console.WriteLine(stringId.Value); // Output: user-123 // Comparison operators work for all types var id1 = new IntId(10); var id2 = new IntId(20); Console.WriteLine(id1 < id2); // Output: True Console.WriteLine(id1 >= id2); // Output: False ``` -------------------------------- ### Configure backing field types Source: https://github.com/andrewlock/stronglytypedid/blob/master/README.md Specify the backing type for an ID using the Template enum or use the default Guid type. ```csharp using StronglyTypedIds; [StronglyTypedId] public partial struct FooId { } var id = new FooId(Guid.NewGuid()); ``` ```csharp using StronglyTypedIds; [StronglyTypedId(Template.Int)] public partial struct FooId { } var id = new FooId(123); ``` -------------------------------- ### Parsing and TryParsing GUIDs to MyId Source: https://github.com/andrewlock/stronglytypedid/blob/master/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateMultipleTemplatesWithBuiltIn.verified.txt Provides static methods to parse a ReadOnlySpan into a MyId object, with a TryParse overload for safe parsing. These methods delegate to the underlying System.Guid parsing methods. ```APIDOC ## Parse and TryParse MyId from Span ### Description These methods allow parsing a character span into a `MyId` object. `Parse` throws an exception on failure, while `TryParse` returns a boolean indicating success or failure. ### Methods #### `public static MyId Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider)` Parses a span of characters into a `MyId` object. #### `public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out MyId result)` Attempts to parse a span of characters into a `MyId` object. Returns `true` if successful, `false` otherwise. ### Implementation Notes - Leverages `global::System.Guid.Parse` and `global::System.Guid.TryParse`. - Conditional compilation (`#if NET7_0_OR_GREATER`) is used for .NET 7+ specific overloads and features. ``` -------------------------------- ### Create a custom template using Roslyn CodeFix Source: https://github.com/andrewlock/stronglytypedid/blob/master/README.md When a custom template specified in [StronglyTypedId] does not exist, the Roslyn CodeFix provider can help create it. The generated template's backing type (Guid, int, long, or string) is inferred from the template name. ```csharp [StronglyTypedId("some-int")] // does not exist public partial struct MyStruct { } ``` -------------------------------- ### Configure Project Reference Source: https://github.com/andrewlock/stronglytypedid/blob/master/README.md Add the PackageReference to your .csproj file with appropriate assets configuration to prevent runtime dependency issues. ```xml Exe net6.0 ``` -------------------------------- ### Configure EF Core with StronglyTypedId Source: https://context7.com/andrewlock/stronglytypedid/llms.txt Demonstrates manual ValueConverter configuration and the recommended .NET 6+ convention-based approach for EF Core. ```csharp using Microsoft.EntityFrameworkCore; using StronglyTypedIds; // Use templates with EF Core support [StronglyTypedId("guid-full")] public partial struct OrderId { } [StronglyTypedId("int-full")] public partial struct ProductId { } public class Order { public OrderId Id { get; set; } public string CustomerName { get; set; } } public class Product { public ProductId Id { get; set; } public string Name { get; set; } public decimal Price { get; set; } } // DbContext with manual converter configuration public class AppDbContext : DbContext { public DbSet Orders { get; set; } public DbSet Products { get; set; } public AppDbContext(DbContextOptions options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity(builder => { builder.Property(x => x.Id) .HasConversion(new OrderId.EfCoreValueConverter()) .ValueGeneratedNever(); }); modelBuilder.Entity(builder => { builder.Property(x => x.Id) .HasConversion(new ProductId.EfCoreValueConverter()) .ValueGeneratedNever(); }); } } // .NET 6+ Convention-based configuration (recommended) public class ConventionDbContext : DbContext { public DbSet Orders { get; set; } public DbSet Products { get; set; } public ConventionDbContext(DbContextOptions options) : base(options) { } protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) { // Apply converters globally for all properties of these types configurationBuilder.Properties() .HaveConversion(); configurationBuilder.Properties() .HaveConversion(); } } // Usage using var context = new AppDbContext(options); context.Database.EnsureCreated(); var order = new Order { Id = OrderId.New(), CustomerName = "Alice" }; context.Orders.Add(order); await context.SaveChangesAsync(); var retrieved = await context.Orders.FirstAsync(); Console.WriteLine(retrieved.Id == order.Id); // Output: True ``` -------------------------------- ### MyId Struct Source: https://github.com/andrewlock/stronglytypedid/blob/master/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateDefaultIdInGlobalNamespace.verified.txt Represents a strongly-typed identifier with a GUID value, including comparison, equality, and formatting capabilities. ```APIDOC ## MyId Struct ### Description A strongly-typed identifier struct that wraps a System.Guid. It provides methods for creating new IDs, checking for empty IDs, and implementing comparison and equality logic. ### Type struct MyId ### Properties - **Value** (System.Guid) - The underlying GUID value of the identifier. ### Methods - **New()** - Creates a new instance of MyId with a new GUID. - **Equals(MyId other)** - Checks if this MyId is equal to another MyId. - **GetHashCode()** - Returns the hash code for this MyId. - **ToString()** - Returns the string representation of the underlying GUID. - **CompareTo(MyId other)** - Compares this MyId with another MyId. ### Operators - **== (MyId a, MyId b)** - Checks for equality between two MyId instances. - **!= (MyId a, MyId b)** - Checks for inequality between two MyId instances. - **> (MyId a, MyId b)** - Checks if the first MyId is greater than the second. - **< (MyId a, MyId b)** - Checks if the first MyId is less than the second. - **>= (MyId a, MyId b)** - Checks if the first MyId is greater than or equal to the second. - **<= (MyId a, MyId b)** - Checks if the first MyId is less than or equal to the second. ### Constants - **Empty** (MyId) - Represents an empty MyId with a GUID.Empty value. ### Interfaces Implemented - System.IComparable - System.IEquatable - System.IFormattable - System.ISpanFormattable (NET6_0_OR_GREATER) - System.IParsable (NET7_0_OR_GREATER) - System.ISpanParsable (NET7_0_OR_GREATER) - System.IUtf8SpanFormattable (NET8_0_OR_GREATER) ``` -------------------------------- ### TryParse string to MyId with provider (NET7_0_OR_GREATER) Source: https://github.com/andrewlock/stronglytypedid/blob/master/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateNonDefaultIdInNamespace.verified.txt Implements IParsable for MyId, providing a TryParse method that accepts a format provider. Returns true if parsing is successful, false otherwise. Requires .NET 7.0 or later. ```csharp public static bool TryParse( [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, global::System.IFormatProvider? provider, out MyId 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; } ``` -------------------------------- ### MyIdSystemTextJsonConverter for System.Text.Json Source: https://github.com/andrewlock/stronglytypedid/blob/master/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdInFileScopedNamespace.verified.txt This JSON converter enables System.Text.Json to serialize and deserialize MyId types directly to and from GUIDs. ```csharp public partial class MyIdSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter { public override MyId Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) => new (reader.GetGuid()); ``` -------------------------------- ### Parse string to MyId with provider (NET7_0_OR_GREATER) Source: https://github.com/andrewlock/stronglytypedid/blob/master/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateNonDefaultIdInNamespace.verified.txt Implements IParsable for MyId, allowing parsing from a string with a specified format provider. Requires .NET 7.0 or later. ```csharp public static MyId Parse(string input, global::System.IFormatProvider? provider) => new(int.Parse(input, provider)); ``` -------------------------------- ### Dapper Type Handler for MyId Source: https://github.com/andrewlock/stronglytypedid/blob/master/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateForCustomTemplate.verified.txt Handles the conversion of MyId to and from database types for Dapper. It supports GUID and string representations. ```csharp public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler { public override void SetValue(global::System.Data.IDbDataParameter parameter, MyId value) { parameter.Value = value.Value.ToGuid(); } public override MyId Parse(object value) { return value switch { global::System.Guid guidValue => new MyId(global::MassTransit.NewId.FromGuid(guidValue)), string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new MyId(global::MassTransit.NewId.FromGuid(result)), _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to MyId"), }; } } ``` -------------------------------- ### MyId Structure Definition Source: https://github.com/andrewlock/stronglytypedid/blob/master/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateMultipleIdsWithSameName.verified.txt The MyId structure provides a strongly-typed wrapper around a Guid, including support for comparison, equality, and serialization. ```APIDOC ## MyId Structure ### Description Represents a strongly-typed identifier based on a System.Guid. It includes built-in support for TypeConverter and System.Text.Json serialization. ### Properties - **Value** (Guid) - The underlying Guid value. ### Methods - **New()** (MyId) - Creates a new MyId with a random Guid. - **Empty** (MyId) - Returns a MyId instance with an empty Guid. - **Equals(MyId other)** (bool) - Compares two MyId instances for equality. - **CompareTo(MyId other)** (int) - Compares the underlying Guid values. ### Converters - **MyIdTypeConverter** - Handles conversion between MyId, Guid, and string types. - **MyIdSystemTextJsonConverter** - Handles JSON serialization and deserialization for MyId. ``` -------------------------------- ### TryFormat Implementation Source: https://github.com/andrewlock/stronglytypedid/blob/master/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateMultipleIdsWithSameName.verified.txt This snippet shows the implementation of the TryFormat method for a strongly typed ID. It is used to format the ID into a UTF-8 byte array. ```csharp global::System.IFormatProvider? provider) => Value.TryFormat(utf8Destination, out bytesWritten, format); #endif } } ``` -------------------------------- ### Parsing and Formatting Source: https://github.com/andrewlock/stronglytypedid/blob/master/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateMultipleTemplatesWithBuiltIn.verified.txt Static methods for parsing strings into MyId and formatting MyId instances. ```APIDOC ## Parsing and Formatting ### Description Provides static parsing capabilities and string formatting support for MyId. ### Methods - **Parse(string)**: Parses a string into a MyId. - **Parse(string, IFormatProvider)**: (NET7+) Parses a string with format provider support. - **TryParse**: (NET7+) Attempts to parse a string into a MyId without throwing exceptions. - **ToString**: Formats the MyId value using standard Guid formatting rules. ``` -------------------------------- ### Parse string to MyId Source: https://github.com/andrewlock/stronglytypedid/blob/master/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanOverrideDefaultsWithCustomTemplateUsingGlobalAttribute.verified.txt Parses a string representation into a `MyId` object. This method expects the input string to be a valid GUID format. ```csharp public static MyId Parse(string input) => new(global::MassTransit.NewId.FromGuid(global::System.Guid.Parse(input))); ``` -------------------------------- ### Define and Apply Custom Templates Source: https://context7.com/andrewlock/stronglytypedid/llms.txt Create custom .typedid files to generate additional code and apply them using the StronglyTypedId attribute. ```csharp // 1. Create a file named "guid-efcore.typedid" in your project // 2. Set Build Action to "AdditionalFiles" or "C# analyzer additional file" // guid-efcore.typedid content: 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 ) { } } } // Use the custom template [StronglyTypedId(Template.Guid, "guid-efcore")] public partial struct OrderId { } // Combine multiple templates [StronglyTypedId(Template.Guid, "guid-efcore", "guid-dapper")] public partial struct ProductId { } // Use only custom templates (no built-in template) [StronglyTypedId("my-custom-guid")] public partial struct CustomId { } // Set custom templates as project defaults [assembly: StronglyTypedIdDefaults(Template.Guid, "guid-efcore", "guid-dapper")] [StronglyTypedId] // Uses Guid + guid-efcore + guid-dapper templates public partial struct DefaultId { } ``` -------------------------------- ### Parse String to MyId Source: https://github.com/andrewlock/stronglytypedid/blob/master/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateNestedIdInFileScopeNamespace.verified.txt Static method to parse a string representation into a MyId object. Requires the input string to be a valid GUID format. ```csharp public static MyId Parse(string input) => new(global::System.Guid.Parse(input)); ``` -------------------------------- ### Define a custom template Source: https://github.com/andrewlock/stronglytypedid/blob/master/README.md Create a .typedid file using PLACEHOLDERID to define custom logic, such as EF Core value converters. ```csharp partial struct PLACEHOLDERID { public 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 ) { } } } ``` -------------------------------- ### Configure Project-Wide Defaults with StronglyTypedIdDefaults Source: https://context7.com/andrewlock/stronglytypedid/llms.txt Use the assembly attribute to define a default backing type for all IDs in the project. Specific IDs can override this default by providing a template in the attribute. ```csharp using StronglyTypedIds; // Set project-wide defaults (place in any file, typically AssemblyInfo.cs or GlobalUsings.cs) [assembly: StronglyTypedIdDefaults(Template.Int)] // These IDs now use int backing type by default [StronglyTypedId] public partial struct OrderId { } // Uses int (from defaults) [StronglyTypedId] public partial struct UserId { } // Uses int (from defaults) [StronglyTypedId] public partial struct CustomerId { } // Uses int (from defaults) // Override defaults for specific IDs [StronglyTypedId(Template.Guid)] public partial struct CorrelationId { } // Uses Guid (overrides default) // Usage var orderId = new OrderId(1001); var userId = new UserId(42); var correlationId = CorrelationId.New(); Console.WriteLine(orderId.Value); // Output: 1001 Console.WriteLine(userId.Value); // Output: 42 Console.WriteLine(correlationId.Value); // Output: 3fa85f64-5717-4562-b3fc-2c963f66afa6 ``` -------------------------------- ### Formatting MyId to Utf8Span Source: https://github.com/andrewlock/stronglytypedid/blob/master/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateMultipleTemplatesWithBuiltIn.verified.txt Implements the IUtf8SpanFormattable interface for efficient UTF-8 formatting into a byte span. This method delegates to the underlying GUID formatting. ```APIDOC ## Formatting MyId to Utf8Span ### Description This method formats the `MyId` object into a UTF-8 byte span, suitable for high-performance scenarios. It delegates to the underlying GUID formatting. ### Method #### `public bool TryFormat(global::System.Span utf8Destination, out int bytesWritten, [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] global::System.ReadOnlySpan format, global::System.IFormatProvider? provider)` Attempts to format the `MyId` object into the provided UTF-8 destination span. ### Parameters - **utf8Destination** (`global::System.Span`) - The span to write the formatted UTF-8 bytes to. - **bytesWritten** (`out int`) - When this method returns, contains the number of bytes written to `utf8Destination`. - **format** (`global::System.ReadOnlySpan`) - Optional format specifier for the GUID. - **provider** (`global::System.IFormatProvider?`) - An object that provides culture-specific formatting information. ### Implementation Notes - Leverages `Value.TryFormat` (where `Value` is the underlying `System.Guid`). - Conditional compilation (`#if NET8_0_OR_GREATER`) is used for .NET 8+ specific features. ``` -------------------------------- ### IParsable implementation Source: https://github.com/andrewlock/stronglytypedid/blob/master/test/StronglyTypedIds.Tests/Snapshots/UnknownTemplateCodeFixProviderUnitTests.UsesBuiltInTemplates_String.verified.txt Implements the IParsable interface for parsing PLACEHOLDERID from a string with an optional format provider. ```csharp public static PLACEHOLDERID Parse(string input, global::System.IFormatProvider? provider) => new(input); ``` ```csharp 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; } ``` -------------------------------- ### Formatting MyId to Span Source: https://github.com/andrewlock/stronglytypedid/blob/master/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateMultipleTemplatesWithBuiltIn.verified.txt Implements the ISpanFormattable interface to format the MyId object into a character span. This method delegates to the underlying GUID formatting. ```APIDOC ## Formatting MyId to Span ### Description This method formats the `MyId` object into a character span, allowing for custom formatting using standard GUID format specifiers. ### Method #### `public bool TryFormat(global::System.Span destination, out int charsWritten, global::System.ReadOnlySpan format, global::System.IFormatProvider? provider)` Attempts to format the `MyId` object into the provided destination span. ### Parameters - **destination** (`global::System.Span`) - The span to write the formatted string to. - **charsWritten** (`out int`) - When this method returns, contains the number of characters written to `destination`. - **format** (`global::System.ReadOnlySpan`) - Optional format specifier for the GUID. - **provider** (`global::System.IFormatProvider?`) - An object that provides culture-specific formatting information. ### Implementation Notes - Leverages `Value.TryFormat` (where `Value` is the underlying `System.Guid`). - Conditional compilation (`#if NET7_0_OR_GREATER`) is used for .NET 7+ specific attributes like `StringSyntaxAttribute`. ``` -------------------------------- ### IParsable implementation for PLACEHOLDERID Source: https://github.com/andrewlock/stronglytypedid/blob/master/test/StronglyTypedIds.Tests/Snapshots/UnknownTemplateCodeFixProviderUnitTests.UsesBuiltInTemplates_Int.verified.txt Implements the IParsable interface for parsing PLACEHOLDERID from strings with an optional format provider. Requires .NET 7.0 or later. ```csharp public static PLACEHOLDERID Parse(string input, global::System.IFormatProvider? provider) => new(int.Parse(input, provider)); ``` ```csharp 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; } ``` -------------------------------- ### ToString with format and provider (IFormattable) Source: https://github.com/andrewlock/stronglytypedid/blob/master/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateNonDefaultIdInNamespace.verified.txt Implements IFormattable for MyId, allowing the ID to be formatted as a string using a specified format and format provider. ```csharp 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); ``` -------------------------------- ### EF Core Value Converter for MyId Source: https://github.com/andrewlock/stronglytypedid/blob/master/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateForCustomTemplate.verified.txt Provides a value converter for Entity Framework Core to map MyId to and from GUIDs. It can be configured with mapping hints. ```csharp 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 MyId(global::MassTransit.NewId.FromGuid(value)), mappingHints ) { } } ``` -------------------------------- ### Implement Parsing and Formatting Source: https://github.com/andrewlock/stronglytypedid/blob/master/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateVeryNestedIdInFileScopeNamespace.verified.txt Methods for parsing strings and spans into MyId, and formatting MyId to strings or spans, with support for .NET 7+ IParsable and ISpanParsable interfaces. ```csharp public static MyId Parse(string input) => new(global::System.Guid.Parse(input)); #if NET7_0_OR_GREATER /// public static MyId 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 MyId 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 MyId 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 MyId 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 MyId 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 #if NET8_0_OR_GREATER /// public bool TryFormat( global::System.Span utf8Destination, out int bytesWritten, ``` -------------------------------- ### System.Text.Json Converter for MyId Source: https://github.com/andrewlock/stronglytypedid/blob/master/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateMultipleTemplatesWithBuiltIn.verified.txt Provides a System.Text.Json converter for the MyId type, handling serialization and deserialization to and from GUIDs. This is suitable for modern .NET applications using System.Text.Json. ```csharp public partial class MyIdSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter { public override MyId 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, MyId value, global::System.Text.Json.JsonSerializerOptions options) => writer.WriteStringValue(value.Value); #if NET6_0_OR_GREATER public override MyId 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 MyId property was null"))); public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, MyId value, global::System.Text.Json.JsonSerializerOptions options) => writer.WritePropertyName(value.Value.ToString()); #endif } ``` -------------------------------- ### Try Parse String to MyId with Provider (NET7_0_OR_GREATER) Source: https://github.com/andrewlock/stronglytypedid/blob/master/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateNestedIdInFileScopeNamespace.verified.txt Attempts to parse a string into a MyId object using a specified format provider, returning a boolean indicating success. Available in .NET 7 and later. ```csharp /// public static bool TryParse( [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, global::System.IFormatProvider? provider, out MyId 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; } } ``` -------------------------------- ### Generated StronglyTypedId Struct Source: https://github.com/andrewlock/stronglytypedid/blob/master/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateGenericVeryNestedIdInFileScopeNamespace.verified.txt The generated code includes a struct with a Guid value, standard equality and comparison operators, and necessary type converters for JSON and TypeDescriptor support. ```csharp //------------------------------------------------------------------------------ // // 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 SomeNamespace { public partial class ParentClass where T: new() { internal partial record InnerClass { public partial struct InnerStruct { [global::System.CodeDom.Compiler.GeneratedCodeAttribute("StronglyTypedId", "1.0.0-beta08")] partial struct MyId : #if NET6_0_OR_GREATER global::System.ISpanFormattable, #endif #if NET7_0_OR_GREATER global::System.IParsable, global::System.ISpanParsable, #endif #if NET8_0_OR_GREATER global::System.IUtf8SpanFormattable, #endif global::System.IComparable, global::System.IEquatable, global::System.IFormattable { public global::System.Guid Value { get; } public MyId(global::System.Guid value) { Value = value; } public static MyId New() => new MyId(global::System.Guid.NewGuid()); public static readonly MyId Empty = new MyId(global::System.Guid.Empty); /// public bool Equals(MyId other) => this.Value.Equals(other.Value); public override bool Equals(object? obj) { if (ReferenceEquals(null, obj)) return false; return obj is MyId other && Equals(other); } public override int GetHashCode() => Value.GetHashCode(); public override string ToString() => Value.ToString(); public static bool operator ==(MyId a, MyId b) => a.Equals(b); public static bool operator !=(MyId a, MyId b) => !(a == b); public static bool operator > (MyId a, MyId b) => a.CompareTo(b) > 0; public static bool operator < (MyId a, MyId b) => a.CompareTo(b) < 0; public static bool operator >= (MyId a, MyId b) => a.CompareTo(b) >= 0; public static bool operator <= (MyId a, MyId b) => a.CompareTo(b) <= 0; /// public int CompareTo(MyId other) => Value.CompareTo(other.Value); public partial class MyIdTypeConverter : 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 MyId(guidValue), string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new MyId(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 MyId 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 MyIdSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter { public override MyId Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) => new (reader.GetGuid()); ``` -------------------------------- ### Serialize with Newtonsoft.Json Source: https://context7.com/andrewlock/stronglytypedid/llms.txt Use the community templates package to enable full Newtonsoft.Json support. This includes handling for nullable IDs. ```csharp using Newtonsoft.Json; using StronglyTypedIds; // Use the guid-full template for complete Newtonsoft.Json support [StronglyTypedId("guid-full")] public partial struct OrderId { } [StronglyTypedId("int-full")] public partial struct ProductId { } public class Order { public OrderId Id { get; set; } public ProductId ProductId { get; set; } public string Description { get; set; } } // Serialization var order = new Order { Id = new OrderId(Guid.Parse("550e8400-e29b-41d4-a716-446655440000")), ProductId = new ProductId(42), Description = "Test order" }; var json = JsonConvert.SerializeObject(order, Formatting.Indented); Console.WriteLine(json); // Output: // { // "Id": "550e8400-e29b-41d4-a716-446655440000", // "ProductId": 42, // "Description": "Test order" // } // Deserialization var deserialized = JsonConvert.DeserializeObject(json); Console.WriteLine(deserialized.Id == order.Id); // Output: True Console.WriteLine(deserialized.ProductId.Value); // Output: 42 // Nullable ID support public class EntityWithNullableId { public OrderId? OptionalId { get; set; } } var entity = new EntityWithNullableId { OptionalId = null }; var nullableJson = JsonConvert.SerializeObject(entity); Console.WriteLine(nullableJson); // Output: {"OptionalId":null} ``` -------------------------------- ### Try parse string with IFormatProvider to MyId (NET7_0_OR_GREATER) Source: https://github.com/andrewlock/stronglytypedid/blob/master/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanOverrideDefaultsWithCustomTemplateUsingGlobalAttribute.verified.txt Attempts to parse a string representation into a `MyId` object using a specified `IFormatProvider`. Returns `true` if successful, `false` otherwise. This overload is available on .NET 7.0 and later. ```csharp /// public static bool TryParse( [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, global::System.IFormatProvider? provider, out MyId 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; } } ``` -------------------------------- ### Custom Type Converter for MyId Source: https://github.com/andrewlock/stronglytypedid/blob/master/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateMultipleTemplatesWithBuiltIn.verified.txt Implements a custom type converter for the MyId type, enabling conversion from and to Guid and string. Use this for older .NET frameworks or specific serialization scenarios. ```csharp { 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 MyId(guidValue), string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new MyId(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 MyId 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); } } ```