Когда вы выполняете Dependency Injection и вам необходимо создавать экземпляры определенного типа для определенного интерфейса, рекомендуется создать специализированных фабричных классов.Это позволяет вам использовать именованный аргумент без фактического внедрения контейнера.
Пример
Это абстрактный тип, который вы будете вводить:
public interface ISerializerFactory
{
ISerializer GetSerializer(string name);
}
Вотконкретный тип, который использует ваш контейнер (StructureMap):
public class StructureMapSerializerFactory : ISerializerFactory
{
public ISerializer GetSerializer(string name)
{
return ObjectFactory.GetNamedInstance<ISerializer>(name);
}
}
Тогда ваш класс будет выглядеть следующим образом:
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);
}
}
Я написал это прохождение "Json"вместо «JsonSerializer», который не будет работать автоматически.Но я думаю, что вы должны изменить свои регистрационные имена, чтобы исключить избыточный суффикс "Serializer" (мы уже знаем, что это сериализатор, потому что мы запрашиваем ISerializer
).Другими словами, создайте метод, подобный этому:
private static string ExtractSerializerName(Type serializerType)
{
string typeName = serializerType.Name;
int suffixIndex = typeName.IndexOf("Serializer");
return (suffixIndex >= 0) ?
typeName.Substring(0, suffixIndex - 1) : typeName;
}
И зарегистрируйте его следующим образом:
scanner.AddAllTypesOf<ISerializer>().NameBy(type => ExtractSerializerName(type));
Тогда вы можете просто использовать строку «Json» для ее создания вместо «JsonSerializer».", который будет выглядеть немного менее уродливо и чувствовать себя менее связанным.
Если вам не нравятся жестко запрограммированные строки, то вы можете создать перечисление для своей фабрики:
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());
}
}
Поэтому вместо того, чтобы писать это:
ISerializer serializer = serializerFactory.GetSerializer("Json");
Вместо этого вы можете написать:
ISerializer serializer =
serializerFactory.GetSerializer(SerializationFormat.Json);
Что будет менее подвержено ошибкам в долгосрочной перспективе.
Это, вероятно, будет более легким в обслуживании в долгосрочной перспективе, потому что если вы начнете изменять имена классов сериализаторов и / или имена будут несовместимыми, то вы можете заменить простой ToString()
на оператор switch
и фактически сопоставлять значения перечисления с именами классов, которые вы регистрируете.
Я бы, вероятно, поместил весь этот код - включая код автоматической регистрации в вашем вопросе - в то же пространство имен или даже в то же самоекод фиle, чтобы ясно указать, что все эти части взаимозависимы.