Closed mikechristiansenvae closed 9 months ago
You can already do this, I'm doing something similar in one of my private projects.
Using [StronglyTypedId(backingType: StronglyTypedBackingType.String)]
would allow you to store the Value
as the slash delimited path from your ToString
methods and there's nothing stopping you adding additional properties to track the StoreId
and SectionId
.
The only drawback would be you'd get a constructor that would allow you to create an instance with a raw string value however my PR #79 would resolve this by being able to disable the generation of the constructor.
Sorry for the delay with this 😳. I'm currently working on a big redesign of the library in this PR:
The main idea is to make the library much more maintainable while also giving people a mechanism to customise the generated IDs as much as they like. This will make it easy to make changes like this 🙂
For what its worth, I ended up implementing this in my project, but I also needed to have some limited inheritance.
To reuse the example I gave above, suppose I had
public readonly record struct StoreId(int Id)
{
public string ToString() => Id.ToString();
}
public readonly record struct GroceryStoreId(int Id) : StoreId(Id) // Uh oh! Can't inherit from a struct!!
{
}
So, to handle inheritance, I needed to use a reference type. But, I did not want to incur the cost of instantiation each time. Additionally, I would want to be able to use ReferenceEquals
for speed.
Looking back, I knew that XNamespace
and XName
atomized their values. So, I lifted XHashtable<TValue>
from the dotnet repo (MIT license). I modified XHashtable<TValue>
to support keys (and renaming it to IdAtomizer<TKey, TValue>
.
Then, I have some abstract base classes:
BaseId<TKey>
, with a protected static method (named Get
) to get or create an instance with a given ID (int
, string
, whatever)BaseId<TParent, TKey>
, with a protected static method (named Get
) to get or create an instance with a given parent and a given ID (int
, string
, whatever)IntegerBaseId
(inherits BaseId<int>
) and IntegerBaseId<TParent>
(inherits BaseId<TParent, int>
), have a protected static method (named GetNext
) to create the "next" ID (auto increment). It also retains the Get
method from its base class, to get an arbitrary instance.Then, derived classes would simply need to add a public static Get
method (and in the case of integer keys, GUIDs, or other key types that can be sequentially or randomly generated, GetNext
) that calls the protected Get
method. (This two step process is required so that the constructor on the derived classes can remain private; a creation delegate is passed). For IDs that are parents, helper (instance) methods are created to allow you to get the next (or specific) child ID.
It works well for me. Other people might like the same approach. If you're interested, I can add the IdAtomizer
and the base classes to an MR for your review.
In one of my applications, I have a set of hierarchical IDs.
Take, for example, if I wanted to have a way to uniquely identify an aisle in a store. Without
StronglyTypedId
, I might do this:Each level of the hierarchy provides a different context. A
SectionId
with an integer value of 1, inStoreId
1 is not the same as aSectionId
with an integer value of 1, inStoreId
2It would be nice if I could do something similar with
StronglyTypedId
.