{"id":18996029,"url":"https://github.com/erri120/transparentvalueobjects","last_synced_at":"2025-04-22T13:49:31.091Z","repository":{"id":204900177,"uuid":"712873678","full_name":"erri120/TransparentValueObjects","owner":"erri120","description":"Source generator for Value Objects.","archived":false,"fork":false,"pushed_at":"2025-03-01T11:40:01.000Z","size":144,"stargazers_count":8,"open_issues_count":10,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-17T03:08:14.575Z","etag":null,"topics":["source-generator"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/erri120.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-11-01T11:33:04.000Z","updated_at":"2025-03-01T11:40:04.000Z","dependencies_parsed_at":null,"dependency_job_id":"0d68bff8-2a60-4571-83c5-ef4c8cf89dc7","html_url":"https://github.com/erri120/TransparentValueObjects","commit_stats":null,"previous_names":["erri120/transparentvalueobjects"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/erri120%2FTransparentValueObjects","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/erri120%2FTransparentValueObjects/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/erri120%2FTransparentValueObjects/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/erri120%2FTransparentValueObjects/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/erri120","download_url":"https://codeload.github.com/erri120/TransparentValueObjects/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250252252,"owners_count":21399962,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["source-generator"],"created_at":"2024-11-08T17:33:41.825Z","updated_at":"2025-04-22T13:49:31.070Z","avatar_url":"https://github.com/erri120.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TransparentValueObjects\n\nSource generator and analyzer to create Value Objects.\n\n## Example\n\n```csharp\nusing System;\nusing TransparentValueObjects;\n\n[ValueObject\u003cGuid\u003e]\npublic readonly partial struct MyId { }\n```\n\nThe attribute `ValueObject\u003cTInnerValue\u003e` will generate a partial implementation of this readonly struct with the following defaults:\n\n- A `public readonly TInnerValue Value` field.\n- A `public static T From(TInnerValue innerValue)` method that uses the private constructor.\n- A private constructor used by the `From` method.\n- A public constructor marked as `Obsolete` with `error: true` that will throw an exception if called (this behavior can be overwritten using [Augments](#augments)).\n- `GetHashCode` and `ToString` implementations that call the same methods on the inner value.\n- Equality methods: `object.Equals`, `IEquatable\u003cT\u003e` and `IEquatable\u003cTInnerValue\u003e`.\n  - `==` and `!=` operators.\n  - Additional `Equals` method with `IEqualityComparer\u003cTInnerValue\u003e` parameter.\n- Explicit cast operators.\n- `IComparable\u003cT\u003e` and `IComparable\u003cTInnerValue\u003e` if `TInnerValue` implements `IComparable\u003cTInnerValue\u003e`.\n  - `\u003c`, `\u003c=`, `\u003e` and `\u003e=` operators.\n- For `Guid` only: `NewId` method that calls `From(Guid.NewGuid())`.\n\nYou can check the [test files](./tests/TransparentValueObjects.Tests/SourceOutput) to view the generated output.\n\n## Augments\n\nThe biggest selling point of this project is the augment feature. You can use the `IAugmentWith` interface to \"augment\" your Value Object with additional functionality:\n\n```csharp\nusing System;\nusing TransparentValueObjects;\n\n[ValueObject\u003cGuid\u003e]\npublic readonly partial struct SampleGuidValueObject : IAugmentWith\u003c\n    DefaultValueAugment,\n    JsonAugment,\n    EfCoreAugment\u003e\n{\n    /// \u003cinheritdoc/\u003e\n    public static SampleGuidValueObject DefaultValue =\u003e From(Guid.Empty);\n}\n```\n\nThe following augments are currently available:\n\n- [`DefaultValueAugment`](#default-value)\n- [`DefaultEqualityComparerAugment`](#default-equality-comparer)\n- [`JsonAugment`](#json-augment)\n- [`EfCoreAugment`](#ef-core-augment)\n\n### Default Value\n\nAugments the Value Object with the `IDefaultValue` interface that has a static member `DefaultValue`:\n\n```csharp\npublic static abstract TValueObject DefaultValue { get; }\n```\n\n```csharp\nusing System;\nusing TransparentValueObjects;\n\n[ValueObject\u003cGuid\u003e]\npublic readonly partial struct SampleGuidValueObject : IAugmentWith\u003cDefaultValueAugment\u003e\n{\n    /// \u003cinheritdoc/\u003e\n    public static SampleGuidValueObject DefaultValue =\u003e From(Guid.Empty);\n}\n```\n\nYou have to implement the `DefaultValue` member when using this augment. The public constructor will now also be available:\n\n```csharp\npublic SampleGuidValueObject()\n{\n    Value = DefaultValue.Value;\n}\n```\n\n### Default Equality Comparer\n\nAugments the Value Object with the `IDefaultEqualityComparer` interface that has a static member `InnerValueDefaultEqualityComparer`:\n\n```csharp\npublic static abstract IEqualityComparer\u003cTInnerValue\u003e InnerValueDefaultEqualityComparer { get; }\n```\n\n```csharp\n[ValueObject\u003cstring\u003e]\npublic readonly partial struct SampleStringValueObject : IAugmentWith\u003cDefaultEqualityComparerAugment\u003e\n{\n    /// \u003cinheritdoc/\u003e\n    public static IEqualityComparer\u003cstring\u003e InnerValueDefaultEqualityComparer =\u003e StringComparer.OrdinalIgnoreCase;\n}\n```\n\nThis default equality comparer will be used by the following methods:\n\n```csharp\npublic bool Equals(SampleStringValueObject other) =\u003e Equals(other.Value);\n\npublic bool Equals(string? other) =\u003e InnerValueDefaultEqualityComparer.Equals(Value, other);\n\npublic override int GetHashCode() =\u003e InnerValueDefaultEqualityComparer.GetHashCode(Value);\n```\n\nThis augment is especially great for strings if you want to always use the case-insensitive equality comparer.\n\n### Json Augment\n\nAugments the Value Object with a JSON converter:\n\n```csharp\n[ValueObject\u003cstring\u003e]\npublic readonly partial struct SampleStringValueObject : IAugmentWith\u003cJsonAugment\u003e { }\n```\n\n**Only** `System.Text.Json` is currently supported! See https://github.com/erri120/TransparentValueObjects/issues/11 for `Newtonsoft.Json` support.\n\n```csharp\n[JsonConverter(typeof(JsonConverter))]\nreadonly partial struct SampleStringValueObject\n{\n    public class JsonConverter : JsonConverter\u003cSampleStringValueObject\u003e { /* omitted */ }\n}\n```\n\nThe `JsonConverterAttribute` will be added to the Value Object, meaning that you can use the added converter without needing to manually add it to the JSON options.\n\nThe source generator will create a custom converter for the following types:\n\n- `string`\n- `Guid`\n- `Int16`\n- `Int32`\n- `Int64`\n- `UInt16`\n- `UInt32`\n- `UInt64`\n\nAll other types will use a fallback converter that fetches an existing converter for `TInnerValue`.\n\n**Note:** If the inner value type is a reference type, like `string`, then you will **need** to also augment the Value Object with the `DefaultValueAugment`.\n\n### EF Core Augment\n\nAugments the Value Object with a `ValueConverter\u003cT, TInnerValue\u003e` and `ValueComparer\u003cT\u003e`:\n\n```csharp\n[ValueObject\u003cstring\u003e]\npublic readonly partial struct SampleStringValueObject : IAugmentWith\u003cEfCoreAugment\u003e { }\n```\n\n```csharp\npublic class EfCoreValueConverter : ValueConverter\u003cSampleStringValueObject, string\u003e\n{\n    public EfCoreValueConverter() : this(mappingHints: null) { }\n\n    public EfCoreValueConverter(ConverterMappingHints? mappingHints = null) : base(\n        static value =\u003e value.Value,\n        static innerValue =\u003e From(innerValue),\n        mappingHints\n    ) { }\n}\n\npublic class EfCoreValueComparer : ValueComparer\u003cSampleStringValueObject\u003e\n{\n    public EfCoreValueComparer() : base(\n        static (left, right) =\u003e left.Equals(right),\n        static value =\u003e value.GetHashCode(),\n        static value =\u003e From(value.Value)\n    ) { }\n\n    /// \u003cinheritdoc/\u003e\n    public override bool Equals(SampleStringValueObject left, SampleStringValueObject right) =\u003e left.Equals(right);\n\n    /// \u003cinheritdoc/\u003e\n    public override SampleStringValueObject Snapshot(SampleStringValueObject instance) =\u003e From(instance.Value);\n\n    /// \u003cinheritdoc/\u003e\n    public override int GetHashCode(SampleStringValueObject instance) =\u003e instance.GetHashCode();\n}\n```\n\n## License\n\nSee [LICENSE](./LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ferri120%2Ftransparentvalueobjects","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ferri120%2Ftransparentvalueobjects","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ferri120%2Ftransparentvalueobjects/lists"}