与 StructureMap 4.6 瞬态生命周期混淆
Confusion with StructureMap 4.6 Transient Lifecycle
我正在使用 StructureMap 4.6 作为我的 IoC 容器。我对它的生命周期有点困惑。正如我在其文档中所读到的,Transient 将为每个容器创建一个对象实例。 Supported Lifecycles
我正在通过创建一个简单的控制台应用程序项目来检查这种情况。我的代码如下:
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);
}
}
当我运行申请时结果是:
我的问题是,当我解析 IFileService
的实例时,我希望每个容器获得一个 FileService
的实例。但是,如您所见,它给出了两个不同的实例。为什么会这样?
您对 documentation 的理解不正确。
- 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
您正在使用 Transient,这意味着每次 Resolve
被调用时您都会得到一个实例 。
但是您描述的行为是针对 Singleton,这意味着创建实例 仅在第一次 Resolve
被调用时 [=64] =].
要获得您想要的行为,您必须将注册类型更改为 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?
单例 VS 瞬态示例
考虑这一点的最简单方法是展示一个示例而不 使用 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
我正在使用 StructureMap 4.6 作为我的 IoC 容器。我对它的生命周期有点困惑。正如我在其文档中所读到的,Transient 将为每个容器创建一个对象实例。 Supported Lifecycles
我正在通过创建一个简单的控制台应用程序项目来检查这种情况。我的代码如下:
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);
}
}
当我运行申请时结果是:
我的问题是,当我解析 IFileService
的实例时,我希望每个容器获得一个 FileService
的实例。但是,如您所见,它给出了两个不同的实例。为什么会这样?
您对 documentation 的理解不正确。
- 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
您正在使用 Transient,这意味着每次 Resolve
被调用时您都会得到一个实例 。
但是您描述的行为是针对 Singleton,这意味着创建实例 仅在第一次 Resolve
被调用时 [=64] =].
要获得您想要的行为,您必须将注册类型更改为 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?
单例 VS 瞬态示例
考虑这一点的最简单方法是展示一个示例而不 使用 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