When you do dependency injection and should be able to create specially typed instances of this interface, the recommended solution is to create specialized factory classes. This allows a named argument to be used without actually entering the container.
Example
This is the abstract type that you will enter:
public interface ISerializerFactory { ISerializer GetSerializer(string name); }
Here is the specific type your container uses (StructureMap):
public class StructureMapSerializerFactory : ISerializerFactory { public ISerializer GetSerializer(string name) { return ObjectFactory.GetNamedInstance<ISerializer>(name); } }
Then your class will look like this:
public class MyClass { private readonly ISerializerFactory serializerFactory; public MyClass(ISerializerFactory serializerFactory) { if (serializerFactory == null) throw new ArgumentNullException("serializerFactory"); this.serializerFactory = serializerFactory; } public string SerializeSomeData(MyData data) { ISerializer serializer = serializerFactory.GetSerializer("Json"); return serializer.Serialize(data); } }
I wrote this passage "Json" instead of "JsonSerializer", which will not automatically work. But I think you should change your login names to eliminate the excessive suffix Serializer (we already know this serializer, because we ask for ISerializer ). In other words, create a method like this:
private static string ExtractSerializerName(Type serializerType) { string typeName = serializerType.Name; int suffixIndex = typeName.IndexOf("Serializer"); return (suffixIndex >= 0) ? typeName.Substring(0, suffixIndex - 1) : typeName; }
And register it as follows:
scanner.AddAllTypesOf<ISerializer>().NameBy(type => ExtractSerializerName(type));
Then you can simply use the "Json" line to create it instead of the "JsonSerializer", which will look a little less ugly and feel less connected.
If you don't like hard-coded strings, then another thing you can do is create an enumeration for your factory:
public enum SerializationFormat { Json, Bson, Xml }; public interface ISerializerFactory { ISerializer GetSerializer(SerializationFormat format); } public class StructureMapSerializerFactory : ISerializerFactory { public ISerializer GetSerializer(SerializationFormat format) { return ObjectFactory.GetNamedInstance<ISerializer>(format.ToString()); } }
So, instead of writing this:
ISerializer serializer = serializerFactory.GetSerializer("Json");
You can write this instead:
ISerializer serializer = serializerFactory.GetSerializer(SerializationFormat.Json);
In the long run, this will be less error prone.
It will probably be more convenient to maintain in the long run, because if you start changing the class names of your serializers and / or the names are incompatible, you can replace the simple ToString() with a switch and actually display the enum values โโfor the class names. which you register.
I would probably put all this code, including the automatic registration code in your question, in the same namespace or even in the same code file to clearly indicate that these parts are interdependent.