1

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

4

4 回答 4

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变量)并在构造函数中进行所有初始化。这只是避免了将变量初始化到类中不同位置的混乱,从而提高了可维护性。

于 2013-01-29T14:27:29.427 回答
2

正如大家所提到的,它可以规避和破坏您的设计模式。但是看看推荐的用法GetSafeUninitializedObject

根据MSDN

只有当用户打算立即填充所有字段时,应使用GetSafeUninitializedObject进行反序列化。它不会创建未初始化的字符串,因为创建不可变类型的空实例没有任何意义。

于 2013-01-29T14:32:32.723 回答
1

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

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

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

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

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

于 2013-01-29T14:24:00.397 回答
1

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

于 2013-01-29T14:25:04.593 回答