c# - 整个应用程序所需的对象

标签 c# singleton

我有一个应用程序,它在应用程序加载时从用户那里获取一些数据,并且在整个应用程序中都需要这些数据,在应用程序的整个生命周期中保留保存这些数据的对象的最佳方法是什么?

此数据需要对应用程序生命周期内创建的大多数其他对象可用。

前几天我了解到单例不一定是个好主意。尤其是在我的应用程序所在的多线程环境中。

我一直在使用 Singletons 来处理这个问题,但我想知道这是否是处理这个问题的好方法?

编辑:

让我详细说明一下:我在应用程序启动时要求输入用户名和密码,现在我知道在内存中保留密码是不安全和不好的做法,但在整个登录过程中有很多地方我需要这个数据来检查各种东西,所以这是我使用单例的地方。

最佳答案

我建议不要使用定义自己的单例的类,因为这通常意味着您在单元测试期间会遇到麻烦。

如果您使用通用单例,您将拥有相同的功能,但在稍后测试/摆脱单例模式(例如,转向多用户)时会有额外的好处。

请注意,单例是使用委托(delegate)初始化的。这里的基本原理是委托(delegate)只会被调用一次,即使两个线程以某种方式同时注册单例......

使用接口(interface)让您在编写单元测试时更轻松,因为您可以模拟您对测试感兴趣的单例部分(或者您的超快 - 在演示给 CEO 补丁/调试 session 之前 2 分钟)。

存储登录/密码元组可能有点矫枉过正,但这种模式保存我培根的次数比我计算的要多。

public static class Singleton<T>
{
    private static T instance;
    private static readonly object sync = new object();
    static bool registered = false;

    public static T Instance
    {
        get
        {
            return instance;
        }
    }

    public static void Register(Func<T> constructor)
    {
        lock (sync)
        {
            if (!registered)
            {
                instance = constructor();
                registered = true;
            }
        }
    }
}

class Demo
{
    class Data
    {
        public string Pass { get; set; }
        public string Login { get; set; }
    }

    void SimpleUsage()
    {
        string login = "SEKRIT";
        string pass = "PASSWORD";

        // setup 
        Singleton<Data>.Register(() => new Data { Login = login, Pass = pass });

        // 
        var ltCommander = Singleton<Data>.Instance;
    }

    /// <summary>
    /// Using an interface will make the singleton mockable for tests! 
    /// That's invaluable when you'll want to fix something FAST without running the whole app!
    /// </summary>
    interface IData
    {
        string Login { get; }
        string Password { get; }
    }

    class UnitTestFriendlyData : IData
    {
        public UnitTestFriendlyData(string login, string password)
        {
            Login = login;
            Password = password;
        }


        public string Login { get; private set; }
        public string Password { get; private set; }
    }

    void SmarterUsage()
    {
        // same setup, but through the interface. 
        Singleton<IData>.Register(() => new UnitTestFriendlyData("login", "pass"));

        // and same for the retrieval
        var data = Singleton<IData>.Instance;

    }


    void UnitTestSetupWithMoq()
    {
        // Register a mock.
        var mock = new Mock<IData>();
        mock.SetupProperty(x => x.Login, "Login");
        mock.SetupProperty(x => x.Pass, "Pass");
        Singleton<IData>.Register(() => mock.Object);

        // and same for the retrieval
        var data = Singleton<IData>.Instance;

    }

}

关于c# - 整个应用程序所需的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1928264/

相关文章:

Android 一个 MediaPlayer 实例 - 单例

c# - 如何关闭线程 'Win32 Thread' (0x1bfc) 的日志已退出,代码为 0 (0x0)?

c# - iPad 上的 MonoTouch : How to make text search faster?

c++ - 派生类中的显式模板静态成员实例化

c++ - 对 Singleton 类的静态成员函数的 undefined reference

java - Java中枚举单例有什么用?

c# - EPPlus:创建排序列

c# - 更改 SearchView 文本颜色 Xamarin.Android

c# - UNITY C# - 如何获取标有自定义属性(字段)的类实例的所有字段?

multithreading - 双重检查锁定的此修复程序有什么问题?