关于c#:我创建的这个单身人士有什么问题

What's wrong with this singleton I created

我创建了一个类,它允许访问全局变量,而只创建一次变量,本质上是一个单例变量。

但是,它与实现单例的任何"正确"方法都不匹配。我假设没有提到它,因为它有一些"错误",但是除了缺少延迟初始化之外,我看不到它有任何问题。

有什么想法吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
static class DefaultFields
{
    private static readonly string IniPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),"defaultFields.ini");
    private static readonly IniConfigSource Ini = GetIni();              

    /// <summary>
    /// Creates a reference to the ini file on startup
    /// </summary>
    private static IniConfigSource GetIni()
    {
        // Create Ini File if it does not exist
        if (!File.Exists(IniPath))
        {
            using (FileStream stream = new FileStream(IniPath, FileMode.CreateNew))
            {
                var iniConfig = new IniConfigSource(stream);
                iniConfig.AddConfig("default");
                iniConfig.Save(IniPath);
            }
        }

        var source = new IniConfigSource(IniPath);
        return source;
    }

    public static IConfig Get()
    {
        return Ini.Configs["default"];
    }

    public static void Remove(string key)
    {
        Get().Remove(key);
        Ini.Save();
    }

    public static void Set(string key, string value)
    {
        Get().Set(key, value ??"");
        Ini.Save();
    }
}


它不遵循通常的单例模式,因为类是静态的,只控制对静态变量的访问。

其中,作为singleton通常是类的静态单个实例,其中唯一的静态函数是创建和访问将变量存储为普通非静态成员变量的singleton。

这意味着类可以很容易地被更改或多次实例化,但您的类不能。


关于singleton,您是对的,它是一个具有唯一实例的类,提供全局访问。

它看起来像一个静态类,但通常以不同的方式实现。

还请记住,使用此模式时应该采取一些预防措施,因为一旦代码很深,就很难重构出单例模式。应该主要在您有硬件限制或实现工厂的唯一访问点时使用。我会尽量避免。

实现的示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class A
{
    /// <summary>
    /// Unique instance to access to object A
    /// </summary>
    public static readonly A Singleton = new A();

    /// <summary>
    /// private constructor so it can only be created internally.
    /// </summary>
    private A()
    {
    }

    /// <summary>
    /// Instance method B does B..
    /// </summary>
    public void B()
    {
    }
}

可以像

A.Singleton.B()

希望有帮助。


我看到的最大问题是,您没有对in i文件执行任何SyncLock操作-试图同时写入值的多个线程可能会以不可预知的结果结束,例如写入和仅一个持久化(或多个线程试图同时写入文件,导致IO错误)。

我将创建某种类型的私有"锁定"对象,然后将写入文件的内容包装在SyncLock中,以确保一次只有一个线程能够更改值(或者至少提交对in i文件的更改)。


类中的所有方法都是静态的,因此您要对用户隐藏单个实例。通过单实例模式,单个实例通过公共属性(通常称为EDCOX1 OR 0)公开(在其他语言如Java中,它可能是一种称为GETSimple或类似方法)。

alt text

你的代码没有错——只是不是单例模式。如果您希望实现一个singleton,我将推荐jon skeet的文章使用C语言实现singleton模式。


对于单例类,延迟初始化非常重要。通过将类声明为静态类,可以实现静态类,而不是单例类。


我也对这个问题的答案感兴趣。在我看来,有大量使用懒惰实例化的单例实例,但我认为您必须问问自己,在具体情况的基础上,它是否真的是必要的。

虽然本文涉及Java,但概念仍然应该适用。这为不同的单例实现提供了许多示例。http://www.shaunabram.com/singleton-implementations/

我还见过很多引用"有效Java"的书,第71条——明智地使用惰性实例化。基本上,除非你需要,否则不要这样做。


为什么是ini字段上的readonly?

但是如果您想要实现单例模式,它是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
static DefaultFields
{
    private readonly string IniPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),"defaultFields.ini");
    private readonly IniConfigSource Ini = GetIni();              

    private static DefaultFields _default;

    public static DefaultFields Default
    {
        get { if(this._default == null){ this._default = new DefaultFields(); } return this._default; }
    }

    private DefaultFields()
    {

    }

    /// <summary>
    /// Creates a reference to the ini file on startup
    /// </summary>
    private IniConfigSource GetIni()
    {
        // Create Ini File if it does not exist
        if (!File.Exists(IniPath))
        {
            using (FileStream stream = new FileStream(IniPath, FileMode.CreateNew))
            {
                var iniConfig = new IniConfigSource(stream);
                iniConfig.AddConfig("default");
                iniConfig.Save(IniPath);
            }
        }

        var source = new IniConfigSource(IniPath);
        return source;
    }

    public IConfig Get()
    {
        return Ini.Configs["default"];
    }

    public void Remove(string key)
    {
        Get().Remove(key);
        Ini.Save();
    }

    public void Set(string key, string value)
    {
        Get().Set(key, value ??"");
        Ini.Save();
    }
}

这不是单例的,而是一个静态类。

在许多方面,静态类类似于单例类,是的。但是静态类不能实现接口,不能从基类继承功能,并且不能对它们进行引用。