代码之家  ›  专栏  ›  技术社区  ›  Navid K

与StructureMap 4.6瞬态生命周期混淆

  •  3
  • Navid K  · 技术社区  · 6 年前

    我使用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();
            });
        }
    }
    

    IFileSerivce。反恐精英

    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);
        }
    }
    

    运行应用程序时,结果是:

    Output

    我的问题是何时解决 IFileService ,我希望得到 FileService 每个容器。但是,正如你所看到的,它给出了两个不同的例子。为什么会这样?

    1 回复  |  直到 6 年前
        1
  •  5
  •   Community Dai    4 年前

    您对 documentation 不正确。

    • 瞬态—默认生命周期。为每个逻辑请求创建一个新对象,以解析容器中的对象图。
    • Singleton--只为容器和该容器创建的任何子容器或嵌套容器创建一个对象实例

    您正在使用 转瞬即逝的 ,这意味着您将获得一个实例 每一次 Resolve 被称为 .

    但你描述的行为 单身汉 ,即创建实例 只有第一次 决定 被称为 .

    要获得所需的行为,必须将注册类型更改为 单身汉 .

    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; } }
    }
    

    容器

    在我们的容器中,我们注册了 Service ,一个单态和一个瞬态。singleton仅被实例化 每个容器实例一次 . 瞬态被实例化 每一次 决定 被称为 .

    public class MyContainer
    {
        private readonly Service singleton = new Service();
    
        public Application Resolve()
        {
            return new Application(
                singleton: this.singleton, 
                transient: new Service());
        }
    }
    

    用法

    在实际应用程序中,只有一个 Application . 然而,我们展示了两个 应用 实例来演示服务注册为 Singleton 将是同一容器实例的同一实例。每次都会创建一个瞬态 决定 被调用。

    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();
        }
    }
    

    输出

    应用程序1。转瞬即逝的名称:dc134d4d-75c8-4f6a-a1a5-367156506671 应用程序2。转瞬即逝的名称:f3012ea2-4955-4cfa-8257-8e03a00b1e99

    应用程序1。单身汉。名称:86d06d7d-a611-4f57-be98-036464797a41 应用程序2。单身汉。名称:86d06d7d-a611-4f57-be98-036464797a41