与StructureMap 4.6瞬态生命周期的混淆 [英] Confusion with StructureMap 4.6 Transient Lifecycle
问题描述
我正在使用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屋!