与StructureMap 4.6瞬态生命周期的混淆 [英] Confusion with StructureMap 4.6 Transient Lifecycle

查看:75
本文介绍了与StructureMap 4.6瞬态生命周期的混淆的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用StructureMap 4.6作为我的IoC容器。我对其生命周期有些困惑。正如我在其文档中所阅读的那样,Transient将为每个容器创建对象的单个实例。



我的问题是,当我解析<$ c $的实例时c> IFileService ,我希望每个容器得到一个 FileService 的实例。但是,如您所见,它给出了两个不同的实例。为什么会这样?

解决方案

您对文档不正确。



  • 瞬态-默认生命周期。为每个逻辑请求创建一个新对象,以从容器中解析对象图。

  • Singleton-将仅为该容器创建一个对象实例,并且将创建由该容器创建的任何子容器或嵌套容器该容器


您正在使用 Transient ,这意味着您获得了一个实例每次调用 Resolve


但是您描述的行为是针对 Singleton ,这意味着仅在第一次调用 Resolve 时创建实例


要获取该行为您需要,必须将注册类型更改为 Singleton

 公共类ConsoleRegistry:注册表
{
public ConsoleRegistry()
{
Scan(_ =>
{
_.TheCallingAssembly();
_.With(new SingletonConvention< IFileService> ;());
_.WithDe faultConventions();
});
}
}

内部类SingletonConvention< TPluginFamily> :IRegistrationConvention
{
public void Process(Type type,Registry Registry)
{
if(!type.IsConcrete()||!type.CanBeCreated()||!type .AllInterfaces()。包含(typeof(TPluginFamily)))返回;

注册表.For(typeof(TPluginFamily))。Singleton()。Use(type);
}
}

参考:如何在Singleton的Assembly and Cache中将Structuremap配置为自动扫描类型?


Singleton VS Transient示例


最简单的方法是使用DI容器显示示例


服务


此处我们有一个服务和一个应用程序服务。唯一真正的区别是应用程序服务应是整个应用程序图的

 公共类Service 
{
公共字符串名称{get;私人套装; } = Guid.NewGuid()。ToString();
}

公共类应用程序
{
private readonly服务单例;
私有只读服务瞬态;

公共应用程序(服务单例,服务瞬态)
{
this.singleton = singleton;
this.transient =瞬变;
}

公共服务Singleton {get {return singleton; }}
公共服务瞬变{get {return return; }}
}


容器


在我们的容器中,我们进行注册 Service 的2个实例,一个单例和一个瞬态。每个容器实例只能实例化一次每次调用 Resolve 都会实例化瞬态。

 公共类MyContainer 
{
private readonly服务单例= new Service();

public Application Resolve()
{
return new Application(
singleton:this.singleton,
transient:new Service());
}
}


用法


世界应用程序,则只有一个 Application 实例。但是,我们显示了两个 Application 实例,以证明注册为 Singleton 的服务将是同一实例的同一实例。容器实例。每次调用 Resolve 都会创建一个瞬态。

  class Program 
{
static void Main(string [] args)
{
var container = new MyContainer();

var application1 = container.Resolve();
var application2 = container.Resolve();


Console.WriteLine($ application1.Transient.Name:{application1.Transient.Name});
Console.WriteLine($ application2.Transient.Name:{application2.Transient.Name});
Console.WriteLine();
Console.WriteLine($ application1.Singleton.Name:{application1.Singleton.Name});
Console.WriteLine($ application2.Singleton.Name:{application2.Singleton.Name});

Console.ReadKey();
}
}


输出



application1.Transient.Name:dc134d4d-75c8-4f6a-a1a5-367156506671
application2.Transient.Name:f3012ea2-4955-4cfa-8257-8e03a00b1e99


application1 .Singleton。名称:86d06d7d-a611-4f57-be98-036464797a41
application2.Singleton.Name:86d06d7d-a611-4f57-be98-036464797a41



I am using StructureMap 4.6 as my IoC Container. I am a bit confused about its lifecycles. As I have read in its documentation, Transient will create a single instance of the object per container. Supported Lifecycles

I am checking this scenario by creating a simple Console Application project. My code is as below:

Program.cs

class Program
{
    private static IContainer _Container;
    static void Main(string[] args)
    {
        _Container = Container.For<ConsoleRegistry>();

        var serv1 = _Container.GetInstance<IFileService>();
        Console.WriteLine($"Name: {_Container.Name}");
        Console.WriteLine(serv1.GetUniqueID());

        var serv2 = _Container.GetInstance<IFileService>();
        Console.WriteLine($"Name: {_Container.Name}");
        Console.WriteLine(serv2.GetUniqueID());

        Console.ReadKey();
    }
}

ConsoleRegistry.cs

public class ConsoleRegistry : Registry
{
    public ConsoleRegistry()
    {
        Scan(_ =>
        {
            _.TheCallingAssembly();
            _.WithDefaultConventions();
        });
    }
}

IFileSerivce.cs

public interface IFileService
{
    string Read(string path);

    void Write(string path, string content);

    bool FileExists(string path);

    string GetUniqueID();
}

FileService.cs

public class FileService : IFileService
{
    private static int instanceCounter;
    private readonly int instanceId;

    public FileService()
    {
        this.instanceId = ++instanceCounter;
        Console.WriteLine("File Service is Created.");
    }

    public int UniqueID
    {
        get { return this.instanceId; }
    }

    public string GetUniqueID()
    {
        return UniqueID.ToString();
    }

    public string Read(string path)
    {
        return File.ReadAllText(path);
    }

    public void Write(string path, string content)
    {
        File.WriteAllText(path, content);
    }

    public bool FileExists(string path)
    {
        return File.Exists(path);
    }
}

When I run the application the result is:

My question is when I resolve an instance of IFileService, I have expected to get a single instance of FileService per container. But, as you can see it gives two different instances. Why is that the case?

解决方案

Your understanding of the documentation is incorrect.

  • Transient -- The default lifecycle. A new object is created for each logical request to resolve an object graph from the container.
  • Singleton -- Only one object instance will be created for the container and any children or nested containers created by that container

You are using Transient, which means you get an instance every time Resolve is called.

But the behavior you are describing is for Singleton, which means to create the instance only the first time Resolve is called.

To get the behavior you want, you have to change the registration type to Singleton.

public class ConsoleRegistry : Registry
{
    public ConsoleRegistry()
    {
        Scan(_ =>
        {
            _.TheCallingAssembly();
            _.With(new SingletonConvention<IFileService>());
            _.WithDefaultConventions();
        });
    }
}

internal class SingletonConvention<TPluginFamily> : IRegistrationConvention
{
    public void Process(Type type, Registry registry)
    {
        if (!type.IsConcrete() || !type.CanBeCreated() || !type.AllInterfaces().Contains(typeof(TPluginFamily))) return;

        registry.For(typeof(TPluginFamily)).Singleton().Use(type);
    }
}

Reference: How can I configure Structuremap to auto scan type in Assembly and Cache by Singleton?

Singleton VS Transient Example

The easiest way to think about this is by showing an example without using a DI container.

Services

Here we have a service and an application service. The only real difference here is that the application service is intended to be the entire application graph.

public class Service
{
    public string Name { get; private set; } = Guid.NewGuid().ToString();
}

public class Application
{
    private readonly Service singleton;
    private readonly Service transient;

    public Application(Service singleton, Service transient)
    {
        this.singleton = singleton;
        this.transient = transient;
    }

    public Service Singleton { get { return singleton; } }
    public Service Transient { get { return transient; } }
}

Container

In our container, we register 2 instances of Service, one singleton and one transient. The singleton is only instantiated once per container instance. The transient is instantiated every time Resolve is called.

public class MyContainer
{
    private readonly Service singleton = new Service();

    public Application Resolve()
    {
        return new Application(
            singleton: this.singleton, 
            transient: new Service());
    }
}

Usage

In a real world application, there would only be one instance of Application. However, we are showing two Application instances to demonstrate that a service registered as Singleton will be the same instance for the same container instance. A transient will be created each time Resolve is called.

class Program
{
    static void Main(string[] args)
    {
        var container = new MyContainer();

        var application1 = container.Resolve();
        var application2 = container.Resolve();


        Console.WriteLine($"application1.Transient.Name: {application1.Transient.Name}");
        Console.WriteLine($"application2.Transient.Name: {application2.Transient.Name}");
        Console.WriteLine();
        Console.WriteLine($"application1.Singleton.Name: {application1.Singleton.Name}");
        Console.WriteLine($"application2.Singleton.Name: {application2.Singleton.Name}");

        Console.ReadKey();
    }
}

Output

application1.Transient.Name: dc134d4d-75c8-4f6a-a1a5-367156506671 application2.Transient.Name: f3012ea2-4955-4cfa-8257-8e03a00b1e99

application1.Singleton.Name: 86d06d7d-a611-4f57-be98-036464797a41 application2.Singleton.Name: 86d06d7d-a611-4f57-be98-036464797a41

这篇关于与StructureMap 4.6瞬态生命周期的混淆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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