I'm working on a project in which I use Depency Injection. When registering a set of interfaces and classes, I need to point out the namespaces at which those interfaces and classes are located.
I don't like providing string constants though, mainly because it hurts refactorability. I don't like taking one of the interfaces/classes and get it's namespace either. For example:
typeof(FoodStore.Fruits.IApple).Namespace
because it looks odd having all these arbitrary type names lingering around (why choose IApple
over IOrange
?), only to distract from the actual point of the code. There's simply no sensible rule which type to pick.
I came up with the following solution.
Put a namespace anchor class in every namespace I need to reference:
namespace FoodStore.Fruits
{
/// <summary>
/// Serves as a type based reference to the namespace this class
/// is located in.
/// </summary>
public sealed class _NamespaceAnc开发者_C百科hor
{
}
}
Now I can use:
typeof(FoodStore.Fruits._NamespaceAnchor).Namespace
Whenever I refactor the namespace, I don't have to worry about the DI registrations.
Although this solution satisfies the question's requirements, I'm still not happy because now I have these sort of ugly empty classes hang around. I can't make them internal
because - obviously - the references span across assemblies.
My question is: does anyone know of a more elegant solution?
No, there isn't anything better - namespaces aren't really first class concepts in the CLR, as far as I'm aware. Yes, Type
allows you to ask it for a namespace - but namespaces are really for humans rather than the VM.
Note that unlike in Java, there's no access control at the namespace level. I haven't checked, but I suspect there's no particular metadata token for a namespace.
I can't think of anything about namespaces which would affect the CLR at execution time. Clearly they affect language compilers - but again, that's for the benefit of humans, so that we can organise types hierarchically and avoid specifying that hierarchy at every step.
I'd be concerned here that the namespace (which is really just part of the class name) has functional meaning in your application. If a later maintenance engineer moves some classes around, they may inadvertently break the injection system without realizing it. The error won't become apparent until runtime and could take a while to track down.
In this case, I would prefer a more explicit opt-in, such as using attributes. Here's one possibility:
public class TestInterfaceAttribute : Attribute { }
public interface IMyInjectableService { }
[TestInterface]
public class TestService : IMyInjectableService { }
public class RealService : IMyInjectableService { }
That said, most DI frameworks already either have some form of export meta-data (to help resolve the correct dependency for your particular use case) or are structured in a way that you define the dependency resolutions explicitly.
精彩评论