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

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

c# - 与 StructureMap 4.6  transient 生命周期的混淆-LMLPHP

我的问题是,当我解析 IFileService 的一个实例时,我希望每个容器获得一个 FileService 实例。但是,正如您所看到的,它提供了两个不同的实例。为什么会这样?

最佳答案

您对 documentation 的理解是错误的。

您正在使用 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?
单例 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/

10-12 18:25