views:

69

answers:

2

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 _NamespaceAnchor
    {
    }
}

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?

+3  A: 

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.

Jon Skeet
If not at the namespace level, can it be done at the assembly level? I find myself creating similar empty "marker" classes for each assembly for the sole purpose of StructureMap bootstrapping.
David
@David: An assembly does not have a namespace, nor a default namespace (which is defined on the project level and merely something Visual Studio uses when creating a new class).
Sandor Drieënhuizen
@Sandor: But I think the spirit of the question is the same. Right now my StructureMap bootstrapper is loaded with things like "y => y.Assembly(typeof(AssemblyMarker).Assembly);" where AssemblyMarker is an empty class in that assembly. To inject in implementations from various projects, the bootstrapper needs to reference each project. Similar to the original question, I'm just wondering if there's a better way to reference it.
David
@David: Yes indeed, the spirit is the same. You could calculate the base namespace using reflection, iterating all types in the assembly, determining the left part of the namespace they have in common. There are pitfalls though because nothing stops you from putting all sorts of incoherent namespaces in your assembly so you might want to throw an exception when you encounter anomalies.
Sandor Drieënhuizen
@David: I don't believe there's anything in C# that gives a strongly typed reference type an assembly, I'm afraid. But I suspect there *is* such a think in the CLR.
Jon Skeet
+1  A: 

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.

Dan Bryant
I do realize the risk of types that should stay in the same namespace, ending up in another. But in my case, the types that are very coherent and moving one or two to another namespace would be very illogical. Your suggestion may avoid that risk that but then there would be the risk of accidently omitting the attribute. I'm a huge fan of convention over configuration and I think that keeping sibling classes (under certain conditions) in the same namespace is a sensible convention.
Sandor Drieënhuizen
@Sandor, if that's the case, I actually like your approach of using an anchor class, as that makes it clear that your namespace has a special meaning worth considering. If I was to have to maintain your code 2 years from now, seeing that anchor class would make me think twice about moving things. The anchor would also be a convenient place to attach any meta-data that might later be useful for your namespace, whatever role it's serving in your system (perhaps a 'category' of the classes for injection?) It's also nice that 'Go To Usage' on the anchor takes you to the injection code.
Dan Bryant
@Dan Bryant: good arguments, especially about the 'Go To Usage' feature in VS.
Sandor Drieënhuizen