StructureMap通过注入,而不是服务定位解决依赖 [英] StructureMap resolve dependency through injection instead of service location

查看:472
本文介绍了StructureMap通过注入,而不是服务定位解决依赖的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在项目中,我注册多个 ISerializers 通过组装扫描仪实现。 FWIW这是注册我的 ISerializers

In my project I register many ISerializers implementations with the assembly scanner. FWIW this is the code that registers my ISerializers

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



,然后正确注册

Which then correctly registers

ISerializer (...ISerializer)
Scoped as:  Transient

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

等等。

目前的唯一的办法我已经能够找出如何解决我想要的串行是用硬编码

Currently the only way I've been able to figure out how to resolve the serializer I want is to hardcode a service location call with

jsonSerializer = ObjectFactory.GetNamedInstance<ISerializer>("JsonSerializer");

现在我知道在我的课,我特别想要的jsonSerializer所以有配置规则的方式或类似的,说了ISerializer的连接基础上,属性名命名实例?所以,我可以有

Now I know in my class that I specifically want the jsonSerializer so is there a way to configure a rule or similar that says for ISerializer's to connect the named instance based on the property name? So that I could have

MySomeClass(ISerializer jsonSerializer, ....)

和StructureMap正确解决这种情况?还是我处理这个问题,也许我应该注册一个实现ISerializer,然后就专门使用

And StructureMap correctly resolve this scenario? Or am I approaching this wrong and perhaps I should just register the concrete type that implements ISerializer and then just specifically use

MySomeClass(JsonSerializer jsonSerializer, ....)

有关沿着这些路线与具体类的东西吗?

for something along these lines with the concrete class?

推荐答案

当你正在做的依赖注入,需要能够创造一个给定的接口的特殊类型的情况下,推荐的解决方案是创建的专业的工厂类。这使您可以使用一个命名参数,而不实际注入容器中。

When you're doing Dependency Injection and need to be able to create specially-typed instances of a given interface, the recommended solution is to create specialized factory classes. This allows you to use a named argument without actually injecting the container.

这是抽象类型你会被注入:

This is the abstract type that you'll be injecting:

public interface ISerializerFactory
{
    ISerializer GetSerializer(string name);
}

下面是具体类型,使您的容器(StructureMap)的使用:

Here is the concrete type, which makes use of your container (StructureMap):

public class StructureMapSerializerFactory : ISerializerFactory
{
    public ISerializer GetSerializer(string name)
    {
        return ObjectFactory.GetNamedInstance<ISerializer>(name);
    }
}



那么你的类将如下所示:

Then your class would look like the following:

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,它不会自动运行。但我认为你应该改变你的注册名,以消除多余的串行后缀(我们已经知道这是一个序列化,因为我们要求的 ISerializer )。换句话说创建这样一个方法:

I've written this passing "Json" instead of "JsonSerializer" which won't automatically work. But I think you should change your registration names to eliminate the redundant "Serializer" suffix (we already know it's a serializer because we're asking for an 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;
}

和这样注册它:

scanner.AddAllTypesOf<ISerializer>().NameBy(type => ExtractSerializerName(type));



然后,你可以使用字符串的Json,而不是JsonSerializer的创建,这将看起来有点不太难看,感觉少耦合的。

Then you can just use the string "Json" to create it instead of "JsonSerializer", which will look a little less ugly and feel less coupled.

如果你不喜欢硬编码字符串,那么你可以做的另一件事是你的工厂创建一个枚举

If you don't like the 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");

您去写这个代替:

ISerializer serializer =
    serializerFactory.GetSerializer(SerializationFormat.Json);



这将是从长远来看,不容易出错。

Which is going to be less error-prone in the long run.

这将很可能是因为如果你开始改变你的串行和/或名称的类名称不一致,则可以取代简单的的ToString是从长远来看更容易维护()开关语句,实际上映射枚举值到你的注册类名。

This will probably be more maintainable in the long run because if you start changing the class names of your serializers and/or the names are inconsistent, then you can replace the simple ToString() with a switch statement and actually map the enum values to the class names you're registering.

我可能把所有这些代码 - 包括在你的问题中自动注册代码 - 在同一个命名空间,甚至是相同的代码文件中,清楚地表明,这些作品都是相互依存

I'd probably put all of this code - including the auto-registration code in your question - in the same namespace, or even the same code file, to clearly indicate that these pieces are all interdependent.

这篇关于StructureMap通过注入,而不是服务定位解决依赖的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆