Я использую StructureMap 4.6 в качестве контейнера IOC. Я немного запутался в отношении его жизненных циклов. Как я прочитал в своей документации, переходный момент создаст один экземпляр объекта на контейнер. Поддерживаемые жизненные циклы

Я проверяю этот сценарий, создав простой проект консольного приложения. Мой код выглядит следующим образом:

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

Когда я запускаю приложение, результат:

Output

Мой вопрос в том, когда я разрешаю экземпляр IFileService, я ожидал получить один экземпляр FileService на контейнер. Но, как вы можете видеть, это дает два разных экземпляра. Почему это дело?

3
Navid K 7 Мар 2018 в 19:23

1 ответ

Лучший ответ

Ваше понимание Документация неверна.

  • Переходный - жизненный цикл по умолчанию. Новый объект создается для каждого логического запроса на разрешение графа объектов из контейнера.
  • Синглтон - будет создан только один экземпляр объекта для контейнера и любых дочерних или вложенных контейнеров, созданных этим контейнером.

Вы используете переходные данные , что означает, что вы получаете экземпляр каждый раз 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);
    }
}

Ссылка: Как настроить Structuremap для автоматического сканирования типа в сборке и кэше с помощью синглтона?

Синглтон против переходного примера

Самый простой способ подумать об этом - показать пример без использования контейнера 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

5
Community 20 Июн 2020 в 12:12