我使用StructureMap 4.6作为我的IoC容器。我对它的生命周期有点困惑。正如我在其文档中所读到的,Transient将为每个容器创建一个对象的单个实例。 Supported Lifecycles
我正在通过创建一个简单的控制台应用程序项目来检查这个场景。我的代码如下:
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();
}
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
个实例。但是,正如您所看到的,它给出了两个不同的实例。为什么会这样?
答案 0 :(得分:3)
您对documentation的理解不正确。
- 瞬态 - 默认生命周期。为每个逻辑请求创建一个新对象,以便从容器中解析对象图。
- Singleton - 只为容器和该容器创建的任何子容器或嵌套容器创建一个对象实例
您正在使用 Transient ,这意味着每次调用Resolve
时都会获得 。
但您所描述的行为是针对 Singleton 的,这意味着仅在第一次Resolve
被称为时才创建实例。
要获得所需的行为,您必须将注册类型更改为 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);
}
}
参考:How can I configure Structuremap to auto scan type in Assembly and Cache by Singleton?
考虑这一点的最简单方法是使用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; } }
}
在我们的容器中,我们注册了2个Service
个实例,一个单例和一个瞬态实例。单例仅在每个容器实例时实例化一次。每当Resolve
被调用时,瞬态被实例化。
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
时都会创建一个瞬态。
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.Name:86d06d7d-a611-4f57-be98-036464797a41 application2.Singleton.Name:86d06d7d-a611-4f57-be98-036464797a41