结构图 |如何创建单例实例/始终获得相同的实例

StructureMap | How to create a singleton instance / get always the same instance

我有一个 class UserManagement 并且总是想得到相同的 instance (比如单例模式)。所以我现在的问题是,我总是得到一个新的 instance insted 命名 "Singleton"。我是 StructureMap 的新手。我已经尝试了网站上描述的两个版本 (http://structuremap.github.io/object-lifecycle/) (http://structuremap.github.io/glossary/)。

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        Container container = new Container(new UserManagement());

        //UserManagement instance = container.GetInstance<UserManagement>("Singleton");
        UserManagement instance = container.GetInstance<UserManagement>();
        MessageBox.Show(instance.Test);
    }
}

public interface IUser
{
    void DoSomethingFancy();
}

public class User : IUser
{
    public void DoSomethingFancy()
    {

    }
}

public interface IDatabase
{
    void DoSomething();
}

public class Database : IDatabase
{
    public void DoSomething()
    {

    }
}

public class UserManagement : Registry
{
    public string Test;

    private Container _Container;
    private IUser _User;
    private IDatabase _Database;

    public UserManagement()
    {
        _Container = new Container(_ =>
        {
            _.For<IUser>().Use<User>();
            _.For<IDatabase>().Use<Database>();
        });

        _User = _Container.GetInstance<IUser>();
        _Database = _Container.GetInstance<IDatabase>();

        Test = DateTime.Now.ToString();

        //For<UserManagement>().AddInstances(x =>
        //{
        //    x.Type<UserManagement>().Named("Singleton");
        //});

        For<UserManagement>().Singleton();
    }
}

更新

我的解决方案有 3 个项目

  1. BootstrapperLibrary(class 库 - Bootstrapper
  2. Gui (WpfApp - MainWindow.xaml)
  3. 框架([​​=58=]class 库 - LoginAction - UserManagement

引导程序库

Bootstrapper.cs

public static class Bootstrapper
{
    public static Container Container => _Container ?? (_Container = InitializeContainer());
    private static Container _Container;

    public static Func<Container> InitializeContainer;    
}

App.xaml.cs

public partial class App : Application
{
    public App()
    {
        Bootstrapper.InitializeContainer += InitializeContainer;
    }

    private Container InitializeContainer()
    {
        Container container = new Container(c => c.Scan(scanner =>
        {
            scanner.TheCallingAssembly();
            scanner.WithDefaultConventions();
            scanner.AssembliesFromApplicationBaseDirectory();
        }));
        container.Configure(c =>
            {
                c.ForSingletonOf<UserManagement>();
                c.For<IUser>().Use<UserAdv>();
            }
        );

        return container;
    }
}

MainWindow.xaml

<Window x:Class="Gui.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:myFramework="clr-namespace:MyFramework;assembly=MyFramework"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Button Content="Button" HorizontalAlignment="Left" Margin="383,228,0,0" VerticalAlignment="Top" Width="75">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <myFramework:LoginAction/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>

    </Grid>
</Window>

框架

LoginAction.cs

public class LoginAction : TriggerAction<DependencyObject>
{
    protected override void Invoke(object parameter)
    {
        UserManagement userManagement = Bootstrapper.Container.GetInstance<UserManagement>();
        Console.WriteLine(userManagement.Test); //Just to see if it's still the same instance who holds for example the current user.
    }
}

UserManagement.cs

public interface IUser
{
    string Name { get; }
    void DoSomethingFancy();
}

public class User : IUser
{
    public string Name { get; } = "default";

    public void DoSomethingFancy()
    {

    }
}

public class UserAdv : IUser
{
    public string Name { get; } = "Advanced";

    public void DoSomethingFancy()
    {

    }
}

public interface IDatabase
{
    void DoSomething();
}

public class Database : IDatabase
{
    public void DoSomething()
    {

    }
}

public class UserManagement
{
    public string Test;

    public IUser User;
    private IDatabase _Database;

    public UserManagement(IUser user, IDatabase database)
    {
        User = user;
        _Database = database;

        Test = DateTime.Now.ToString();
    }
}

如果我理解正确,我的主应用程序现在初始化并配置 application startup 中的 ContainerBootstrapper class 在那里持有一个静态实例。 MyFramework 从静态 Container 实例中获取 UserManangement 的实例。

这是StructureMap的正确使用方法吗?感谢您的耐心等待!

您应该声明:

ForConcreteType<UserManagement>().Singleton();

编辑:

您可以实现一个引导程序 class 并在程序启动期间调用 Initialize() 方法:

public sealed class Bootstrapper
{
  private static StructureMap.Container _container;

  public StructureMap.Container MyContainer
  {
    get { return _container; }
  }

  static Bootstrapper() 
  {
  }

  public static Initialize()
  {
    StructureMap.Configuration.DSL.Registry registry = new StructureMap.Configuration.DSL.Registry();

    registry.For<IUser>().Use<User>();
    registry.For<IDatabase>().Use<Database>();
    registry.ForConcreteType<UserManagement>().Singleton();

    _container = new Container(registry);
  }
}

UserManagement class 中删除容器初始化并让 DI 框架注入具体 types/objects.

public class UserManagement
{
    public string Test;

    private IUser     _user;
    private IDatabase _database;

    public UserManagement(IUser user, IDatabase database)
    {
      _user     = user;
      _database = database;

      Test = DateTime.Now.ToString();
    }
}

修改您的 WPF 测试 window:

public partial class MainWindow : Window
{
    static MainWindow()
    {
      // only for demonstration!!!
      Bootstrapper.Initialize();
    }

    public MainWindow()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        Container container = Bootstrapper.MyContainer;

        UserManagement instance = container.GetInstance<UserManagement>();
        MessageBox.Show(instance.Test);
    }
}