C
C#8mo ago
blast2857

Static helper class/method design question

Hello, I have a design question. I'm writing a helper class where the purpose is solely to find types on the assembly (via reflection and making use of certain patterns) for a certain path. Since I may need to get the path multiple times for multiple files I thought that caching it would be the proper way to approach this. But I have a few concerns, I always hear that having state in a static class, in this case the cache is not a good idea. But I also don't really need an instance of the class since all it really is it's a helper so I'm not sure how would I go for designing this in a different way. Likewise, I'm not a fan of the methods existing there but never being "normally" called (only via reflection after being grabbed via the attribute)
internal class FinderAttribute : Attribute {
public string Path { get; init; }
public string Note { get; init; }
}

internal static class FinderHelper {
private static Dictionary<string, Type> _pathCache = new();

public static void FillCache() {
var finders = Assembly.GetExecutingAssembly().GetTypes().SelectMany(t => t.GetMethods(BindingFlags.Static | BindingFlags.NonPublic)).Where(m => m.GetCustomAttribute<FinderAttribute>() != null);
foreach (var finder in finders) {
var attr = finder.GetCustomAttribute<FinderAttribute>();
_pathCache[attr.Path] = (Type)finder.Invoke(null, []);
}
}

public static Type FindTypeForPath(string path) => ...;

[FinderAttribute(Path = "Path1/Path2/", Note = "...")]
private static Type Find1() {
// do logic to find the Type for path 1 in the assembly...
}

[FinderAttribute(Path = "Path1/Path3/", Note = "...")]
private static Type Find2() {
// do logic to find the Type for path 2 in the assembly...
}
}
internal class FinderAttribute : Attribute {
public string Path { get; init; }
public string Note { get; init; }
}

internal static class FinderHelper {
private static Dictionary<string, Type> _pathCache = new();

public static void FillCache() {
var finders = Assembly.GetExecutingAssembly().GetTypes().SelectMany(t => t.GetMethods(BindingFlags.Static | BindingFlags.NonPublic)).Where(m => m.GetCustomAttribute<FinderAttribute>() != null);
foreach (var finder in finders) {
var attr = finder.GetCustomAttribute<FinderAttribute>();
_pathCache[attr.Path] = (Type)finder.Invoke(null, []);
}
}

public static Type FindTypeForPath(string path) => ...;

[FinderAttribute(Path = "Path1/Path2/", Note = "...")]
private static Type Find1() {
// do logic to find the Type for path 1 in the assembly...
}

[FinderAttribute(Path = "Path1/Path3/", Note = "...")]
private static Type Find2() {
// do logic to find the Type for path 2 in the assembly...
}
}
Is this a good design or where could I improve / change it?
4 Replies
Not Mark
Not Mark8mo ago
For testability's sake, I'd personally make this a non-static class with an interface (with _pathCache being a non-static field). You can then register this class as a singleton to be injected into your other classes. Then for the FillCache method, you can either call that in the constructor (although typically you would avoid complex logic like that in a constructor) or maybe call it when registering your class. As for the caching logic, I don't really see a problem with it as long as you know the types for a given path wouldn't change during runtime.
Angius
Angius8mo ago
I'd ask myself if it can be done with a source generator, tbh
blast2857
blast2857OP8mo ago
You mean using dependency injection? I'm worried in this case I may have to pass it around a lot. As for the method I'm not sure where else I'd be able to call it at I tried to experiment a bit with source generators but as far as I saw (I may be completely wrong) I can't easily use reflection on the assembly to find the types?
Angius
Angius8mo ago
That's the neat part, you use the source generator to find the types
Want results from more Discord servers?
Add your server