我使用 StructureMap 4.6 作为我的 IoC 容器。我对它的生命周期有点困惑。正如我在其文档中所读到的,Transient 将为每个容器创建一个对象实例。 Supported Lifecycles
我正在通过创建一个简单的控制台应用程序项目来检查这个场景。我的代码如下:
程序.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();
}
}
控制台注册表
public class ConsoleRegistry : Registry
{
public ConsoleRegistry()
{
Scan(_ =>
{
_.TheCallingAssembly();
_.WithDefaultConventions();
});
}
}
文件服务
public interface IFileService
{
string Read(string path);
void Write(string path, string content);
bool FileExists(string path);
string GetUniqueID();
}
文件服务.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);
}
}
当我运行应用程序时,结果是:
我的问题是,当我解析
IFileService
的一个实例时,我希望每个容器获得一个 FileService
实例。但是,正如您所看到的,它提供了两个不同的实例。为什么会这样? 最佳答案
您对 documentation 的理解是错误的。
您正在使用 Transient,这意味着每次 Resolve
被称为 时,您都会获得一个实例 。
但是您所描述的行为是针对 Singleton 的,这意味着仅在 Resolve
第一次被称为 时才创建实例 。
要获得您想要的行为,您必须将注册类型更改为 Singleton 。
引用:How can I configure Structuremap to auto scan type in Assembly and Cache by 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);
}
}
单例 VS transient 示例
考虑这一点的最简单方法是展示一个不使用 DI 容器的示例。
服务
这里我们有一个服务和一个应用程序服务。这里唯一真正的区别是应用程序服务旨在成为整个应用程序图。
容器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; } }
}
在我们的容器中,我们注册了 Service
的 2 个实例,一个单例和一个 transient 。每个容器实例 单例仅实例化一次 。每次调用 Resolve
时,都会实例化 transient 。
用法public class MyContainer
{
private readonly Service singleton = new Service();
public Application Resolve()
{
return new Application(
singleton: this.singleton,
transient: new Service());
}
}
在现实世界的应用程序中,只有一个 Application
实例。但是,我们展示了两个 Application
实例,以证明注册为 Singleton
的服务将是同一个容器实例的同一个实例。每次调用 Resolve
时都会创建一个 transient 。
输出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();
}
}
关于c# - 与 StructureMap 4.6 transient 生命周期的混淆,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49156716/