静态构造函数 - c#中的单例设计模式

时间:2016-08-25 00:00:21

标签: c# .net design-patterns

如果,我用单例设计模式中的静态构造函数替换私有构造函数?

public sealed class Singleton
{
    private static Singleton instance=null;

    private Singleton()
    {
    }

    public static Singleton Instance
    {
        get
        {
            if (instance==null)
            {
                instance = new Singleton();
            }
            return instance;
        }
    }
}

静态构造函数只会被调用一次,我在实现中找不到任何区别。我们可以用静态构造函数替换private吗?

5 个答案:

答案 0 :(得分:6)

私有构造函数在这种情况下真正做的就是阻止类之外的任何东西实例化类Singleton的实例,这几乎肯定是故意的,因为单例只应该只有一个实例。

静态类构造函数在未知时间运行一次类型,然后才能使用该类型或其任何静态成员。在运行静态构造函数之前初始化静态字段。

所以,我想你可以用静态构造函数替换构造函数,但是这会给你单例类型上的隐式无参数构造函数,这将允许任何人实例化一个实例,这可能与为什么不一致你首先使用的是单例模式。它也不会改变关于你的课程的构建方式,真的,为什么呢?

例如,以下面的类为例:

public class Test { }

由于没有声明的构造函数,C#编译器隐式地将无参数的公共构造函数添加到类中,允许使用者创建实例。

public class Program {
    public static void Main() { 
        var test = new Test();
    }
}

如果您希望能够创建班级实例,这一切都很好。单例模式旨在仅向消费者提供类型的单个实例。我们可以将这个静态实例添加到我们的测试类型中,如下所示:

public class Test { public static Test Instance {get;} = new Test(); }

我们可以像这样得到这个静态实例:

public class Program {
    public static void Main() {
        var test = Test.Instance; // good
        var other = new Test(); // less than ideal
    }
}

所以我们正如预期的那样通过它的实例字段提供对单例对象的访问,但是我们仍然可以创建单例类型的实例,这不太好,因为它违背了单例的目的(即,只有一个共享实例。)

因此我们在该类型中添加一个私有的无参数构造函数。

public class Test { 
    private Test() {}
    public static Test Instance {get;} = new Test(); 
}

向类型添加构造函数将导致C#编译器不添加隐式的无公共参数构造函数。将其设为私有允许在类范围内访问它,该范围用于实例化我们的实例属性,并防止其他任何实例化对象。最终结果是:

public class Program {
    public static void Main() {
        var test = Test.Instance; // good
        var other = new Test(); // Compile time error
    }
}

您的单例对象现在可以防止实例化该类的其他实例,并且使用它的唯一方法是按预期通过实例属性。

答案 1 :(得分:2)

简单来说,如果删除私有构造函数,那么任何人都可以创建Singleton的新实例:

// With the private constructor, the compiler will prevent this code from working.
// Without it, the code becomes legal.
var newInstance = new Singleton();

如果有人能像上面那样实例化Singleton,那么你就不再拥有单身人士了。

答案 2 :(得分:0)

另一种更简洁的方法是在您的私有实例上使用readonly

这是更少的代码,也是线程安全的。 CLR会为您处理所有事情,不需要lock,检查空值和内容。

public sealed class Singleton
{
    private static readonly Singleton _instance = new Singleton();

    public static Singleton Instance {
        get {
                return _instance;
            }            
    }

    private Singleton()
    {
    }
}

然后简单地测试:

[TestMethod]
public void IsSingleton()
{
    Assert.AreSame(Singleton.Instance, Singleton.Instance);
}

编辑:

使用lock

的示例
public sealed class Singleton
{
    private static readonly object _lock = new object();
    private static Singleton instance = new Singleton();

    public static Singleton Instance
    {
        get
        {
            lock(_lock)
            {
                if (instance==null)
                {
                    instance = new Singleton();
                }
                return instance;    
            }
        }
    }

    private Singleton()
    {
    }
}

答案 3 :(得分:0)

简单来说,如果您删除privatedefault public constructor将会曝光。然后外人将被允许使用new Singleton();并生成Singleton类的实例数。所以没有单身人士模式。

此单例模式(private constructor + static getInstance() with either lazy-loading or eager loading)的这种经典实现是如此evil。在现代,您必须转而使用Dependency-Injection框架。

答案 4 :(得分:-2)

这应该可以正常工作。您还可以使类静态和通用,以便您可以在instance中存储任何类型的值。这将有助于分离关注点,保持单例模式和它将包含的类分开。

相关问题