My goal is to have an abstract class representing one of many DAO objects, any of which can be put into an internal cache indexed by a cache key. The actual processing is done in a separate processor class which takes in the specific DAO class as a generic argument. I am trying to figure out how to use the generic argument to determine the correct cache key
what I'm attempting is basically this
abstract class Dao {
// some kind of static string called "CacheKeyStem". The below doesn't work because you can't have abstract static properties
abstract static string CacheKeyStem { get; }
int Id { get; set; }
string CacheKey => $"{CacheKeyStem}-{Id}";
}
PersonDao : Dao {
// override CacheKeyStem. Again, this doesn't work
public static override string CacheKeyStem => "Person";
}
CarDao : Dao {
// override CacheKeyStem. Again, this doesn't work
public static override string CacheKeyStem => "Car";
}
So now we have 2 DAOs, one for persons and one for cars. In my processor class, I have
abstract class BaseProcessor<T> where T : Dao {
public void AddToCache(T obj){
_myCache.Add(obj.CacheKey, obj);
}
public T RetrieveFromCache(int id){
// the below obviously doesnt work either.
return _myCache.Get<T>($"{T.CacheKeyStem}-{id}");
}
}
I'm sure there's a better way to accomplish what I'm trying to do here, but I'm not sure what it is. Within RetrieveFromCache, we know the type of the object we want, but we don't have an instance. We know that the type extends Dao
. I need a way to get the CacheKeyStem based on the type of the generic argument.
You can do it with static interface methods available from C#11 and .NET 7:
For your case, something like this:
interface IHaveCacheKeyStem {
abstract static string CacheKeyStem { get; }
}
abstract class Dao {
public int Id { get; set; }
public string CacheKey => $"{GetCacheKeyStem()}-{Id}";
protected abstract string GetCacheKeyStem();
}
class PersonDao : Dao, IHaveCacheKeyStem {
public static string CacheKeyStem => "Person";
protected override string GetCacheKeyStem() => CacheKeyStem;
}
class CarDao : Dao, IHaveCacheKeyStem {
public static string CacheKeyStem => "Car";
protected override string GetCacheKeyStem() => CacheKeyStem;
}
abstract class BaseProcessor<T> where T : Dao, IHaveCacheKeyStem {
// example cache
Dictionary<string, T> _myCache = new();
public void AddToCache(T obj) {
_myCache.Add(obj.CacheKey, obj);
}
public T RetrieveFromCache(int id) {
// T.CacheKeyStem would work
// dictionary doesn't have Get<T> method though
// so won't compile
return _myCache.Get<T>($"{T.CacheKeyStem}-{id}");
}
}
example use:
var personDao = new PersonDao() { Id = 42 };
Console.WriteLine(personDao.CacheKey); // Person-42
var carDao = new CarDao() { Id = 42 };
Console.WriteLine(carDao.CacheKey); // Car-42