c# - 单例与 GetSafeUninitializedObject

标签 c# reflection singleton system.reflection

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

最佳答案

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

通过调用 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 要求的类型初始化器和静态构造器之间的区别

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

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

参加这个示例类(class):

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

关于c# - 单例与 GetSafeUninitializedObject,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14585029/

相关文章:

android - 在没有任何静态引用的情况下使用上下文

c# - 为什么 Float 转换忽略小数点后的零?

java - Java中带参数的单例

c# - 身份服务器单点注销,也从服务器注销

c# - 线程可以作为另一个用户执行吗? (.NET 2.0/3.5)

c# - 如何在运行时为反射方法创建委托(delegate)

java - 检查方法参数的泛型类型

dart - Singleton在Dart中如何工作?

c# - Azure WebJob 访问被拒绝

c# - 返回从存储过程中仅一个命令删除的行数