在我的项目中,我用汇编扫描器注册了许多ISerializers实现。fwiw这是注册myISerializers

Scan(scanner =>
{
    scanner.AssemblyContainingType<ISerializer>();
    scanner.AddAllTypesOf<ISerializer>().NameBy(type => type.Name);
    scanner.WithDefaultConventions();
});

然后正确注册
ISerializer (...ISerializer)
Scoped as:  Transient

JsonSerializer    Configured Instance of ...JsonSerializer
BsonSerializer    Configured Instance of ...BsonSerializer

等等。
目前,我能够找出如何解析所需序列化程序的唯一方法是硬编码服务位置调用
jsonSerializer = ObjectFactory.GetNamedInstance<ISerializer>("JsonSerializer");

现在我知道在我的类中,我特别想要jsonserializer,那么有没有一种方法可以配置一个规则或类似的规则,让iserializer基于属性名连接命名实例?所以我可以
MySomeClass(ISerializer jsonSerializer, ....)

并且structuremap正确地解决了这个场景?或者我是不是走错路了,也许我应该注册实现ISerializer的具体类型,然后专门使用
MySomeClass(JsonSerializer jsonSerializer, ....)

为了一些具体的课程?

最佳答案

当您正在进行依赖项注入并且需要能够为给定接口创建特殊类型的实例时,建议的解决方案是创建专门的工厂类。这允许您使用命名参数,而无需实际注入容器。
例子
这是将要注入的抽象类型:

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,并实际将枚举值映射到正在注册的类名。
我可能会将所有这些代码——包括您问题中的自动注册代码——放在同一个名称空间中,甚至放在同一个代码文件中,以清楚地表明这些部分都是相互依赖的。

08-04 09:11