Singleton vs GetSafeUninitializedObject

时间:2013-01-29 14:18:23

标签: c# reflection singleton system.reflection

我遇到了Marc Gravell关于如何在不调用构造函数的情况下创建对象的this回答。有人可以确认这不会绕过单例模式的完整和最佳实现(参考实现here。为什么?我想更具体地说我不清楚GetSafeUninitializedObject()在类的上下文中的内部工作原理构造函数(静态,私有等)

4 个答案:

答案 0 :(得分:2)

在单例模式中,您的类型上有一个静态变量,将由类型构造函数初始化。

通过调用GetSafeUninitializedObject,您只能避免使用实例构造函数,> 类型构造函数之后将调用

示例:

public sealed class Singleton
{
    private static readonly Singleton instance = new Singleton();
    private static string _StaticMessage = "Type ctor;";

    private string _Message = "init; ";

    static Singleton()
    { }

    private Singleton()
    {
        _Message += "ctor; ";
    }

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

    public string Message { get { return _StaticMessage + _Message; } }
}

internal class Program
{
    private static void Main(string[] args)
    {
        var singleton = Singleton.Instance;
        // writes "Type ctor;init; ctor;"
        Console.WriteLine(singleton.Message);

        var instance = (Singleton)System.Runtime.Serialization.FormatterServices
        .GetSafeUninitializedObject(typeof(Singleton));

        // writes "Type ctor;"
        Console.WriteLine(instance.Message);
    }
}

更新以澄清从IllidanS4

询问的类型初始化程序和静态ctor之间的区别

这并不属于上面的答案,而是评论中的问题:而答案根本不适用于简单的评论。

@IllidanS4:类型初始值设定项只是用于编写隐式静态构造函数的快捷方式。如果创建一个包含两个初始化方法的类并对生成的程序集进行反编译,则只能看到一个将初始化所有变量的静态构造函数(.cctor)。两个赋值将合并,其中首先调用类型初始化程序,静态构造函数中的语句最后。

参加此示例课程:

internal static class C
{
    public static readonly string ByTypeCtor;
    public static readonly string ByTypeInitializer = "From type init; ";
    public static string ByBoth = "From type init; ";

    static C()
    {
        ByTypeCtor = "From static ctor; ";
        ByBoth += "From static ctor";
    }
}

如果你编译它然后反编译它(例如使用ILSpy)你会得到以下代码:

internal static class C
{
    public static readonly string ByTypeCtor;
    public static readonly string ByTypeInitializer;
    public static string ByBoth;
    static C()
    {
        C.ByTypeInitializer = "From type init; ";
        C.ByBoth = "From type init; ";
        C.ByTypeCtor = "From static ctor; ";
        C.ByBoth += "From static ctor";
    }
}

由于这个事实,我通常不会在声明它时直接初始化变量。相反,我总是将它们保持未初始化(如ByTypeCtor变量)并在构造函数中进行所有初始化。这样可以简单地避免将变量初始化混乱到类中的不同位置,从而提高可维护性。

答案 1 :(得分:2)

正如大家所提到的,可以规避和破坏你的设计模式。 但请查看GetSafeUninitializedObject

的推荐用法

根据MSDN

  当用户打算立即填充所有字段时,

GetSafeUninitializedObject应用于反序列化。它不会创建一个未初始化的字符串,因为创建一个不可变类型的空实例是没有用的。

答案 2 :(得分:1)

是的,在大多数情况下,默认的Singleton模式肯定更好。您的类型的预期行为是必须调用它的ctor。

创建一个对象而不用在该类型上调用ctor方法,这不是“正常”的事情,所以我个人会总是避免使用此解决方案直到真的有充分理由这样做。

旁注:单例模式只是模式而不是框架行为。在我看来,在这个问题中,你混合了两个不混合的概念。

第一种情况是一种创建对象的方式,第二种情况是一种构建代码的方式

一般规则是:不要做“奇怪的事情”(GetSafeUninitializedObject很奇怪),直到你真的需要这样做。保持对所有开发人员模式的共同共享,并尽可能地保持简单。

答案 3 :(得分:1)

GetSafeUninitializedObject方法甚至可以在具有私有构造函数的对象上工作,因此它可能用于规避单例模式。