C
C#•5mo ago
IsNotNull

More Elegant Way to Make a Generic Lookup Type

I want to store things for lookup by a generic type. Case: I have a storage class that I want to expose a Get<T>(string key) method, and internally is uses specialized storage lookup instances for each type. Is the only way to do that today to use a Dictionary<System.Type, AbstractThing> and then cast my AbstractThing to MoreSpecific<T>?
10 Replies
IsNotNull
IsNotNullOP•5mo ago
c#
public class LookupByType
{
Dictionary<Type, object> internalLookup = new();
public void Add<TType>(TType value) => internalLookup.Add(typeof(TType), value);
public TValue Get<TValue>(Type type) => (TValue)internalLookup[type];
}
c#
public class LookupByType
{
Dictionary<Type, object> internalLookup = new();
public void Add<TType>(TType value) => internalLookup.Add(typeof(TType), value);
public TValue Get<TValue>(Type type) => (TValue)internalLookup[type];
}
Omnissiah
Omnissiah•5mo ago
GitHub
protoactor-dotnet/src/Proto.Actor/Utils/TypedDictionary.cs at dev ·...
Proto Actor - Ultra fast distributed actors for Go, C# and Java/Kotlin - asynkron/protoactor-dotnet
IsNotNull
IsNotNullOP•5mo ago
That is just assigning a surrogate integer ID for each type added?
Omnissiah
Omnissiah•5mo ago
yeah
IsNotNull
IsNotNullOP•5mo ago
That would save a few operations per lookup (the hash of the type), so that is cool. It wouldn't save me having to cast the value results, but I'm guessing I'm stuck with that no matter what.
Omnissiah
Omnissiah•5mo ago
in one way or the other there will be sacrifices
IsNotNull
IsNotNullOP•5mo ago
@boiled goose I'll probably just change storageThing.Get<T>(key) to storageThing.Lookup<T>().Get(key) Doesn't avoid the need for a type lookup (that TypedDictionary would be perfect), but I can avoid the casting and if the consumer holds onto a specific lookup reference, then they can avoid the type lookup for all future calls. @boiled goose thanks for the link The lookup type implements a non allocating StartsWith search, and right now to get around the issues of this help post I'm using LINQ to cast the IEnumerable (which boxes the struct enumerator, killing the performance benefit of making the enumerator non-allocating). These changes will look great on my benchmarks 😆
PixxelKick
PixxelKick•5mo ago
If you are in a DI context, you could just register lookups for each T and use an inner scope service provider Though at that point you pretty much reinvented named services that we got recently, can prolly just use that
IsNotNull
IsNotNullOP•5mo ago
That would be a good idea, and is similar to how I plan to consume these types in my own projects. The types though, are in an open source library and I want the library to remain neutral about configuration and dependency choices of the consumer. I won't pressume they are using a specific (or any) DI container.
PixxelKick
PixxelKick•5mo ago
In that case I would just define a lookup interface, and make a few implementation options in sub packages for the consumer to choose how it's backed
Want results from more Discord servers?
Add your server