it-swarm.com.ru

Синглтон от Jon Skeet разъяснения

public sealed class Singleton
{
    Singleton() {}

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

    class Nested
    {
        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static Nested() {}
        internal static readonly Singleton instance = new Singleton();
    }
}

Я хочу реализовать шаблон Singleton Джона Скита в моем текущем приложении на C #.

У меня есть два сомнения в коде

  1. Как можно получить доступ к внешнему классу внутри вложенного класса? Я имею в виду

    internal static readonly Singleton instance = new Singleton();
    

    Что-то называется закрытием?

  2. Я не могу понять этот комментарий

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit
    

    что этот комментарий предлагает нам?

211
amutha
  1. Нет, это не имеет ничего общего с замыканиями. Вложенный класс имеет доступ к закрытым членам своего внешнего класса, включая приватный конструктор.

  2. Прочитайте мой статья о beforefieldinit . Вы можете или не можете хотеть статический конструктор no-op - это зависит от того, что лень гарантирует вам нужно. Вы должны знать, что .NET 4 несколько изменяет фактическую семантику инициализации типа (все еще в пределах спецификации, но ленивее, чем раньше ).

Вам действительно нужен этот шаблон? Вы уверены, что не можете сойти с рук:

public sealed class Singleton
{
    private static readonly Singleton instance = new Singleton();
    public static Singleton Instance { get { return instance; } }

    static Singleton() {}
    private Singleton() {}
}
352
Jon Skeet

Относительно вопроса (1): Ответ от Джона верен, поскольку он неявно помечает класс как "Вложенный" как закрытый, не делая его открытым или внутренним :-). Вы также можете сделать это явно, добавив "private":

    private class Nested

Относительно вопроса (2): в основном, что пост о beforeinitfield и инициализация типа говорит вам, что если у вас нет статического конструктора, среда выполнения может инициализировать его в любое время (но прежде чем использовать его). Если у вас есть статический конструктор, ваш код в статическом конструкторе может инициализировать поля, что означает, что среде выполнения разрешено инициализировать поле только при запросе типа.

Так что, если вы не хотите, чтобы среда выполнения проактивно инициализировала поля перед их использованием, добавьте статический конструктор.

В любом случае, если вы реализуете синглеты, вы либо хотите, чтобы он инициализировался как можно более лениво, а не тогда, когда среда выполнения думает, что должна инициализировать вашу переменную - или вам, вероятно, просто все равно. От твоего вопроса, я полагаю, ты хочешь их как можно позже.

Это знакомит с постом Джона о singleton , который является IMO основной темой этого вопроса. Ох и сомнения :-)

Я хотел бы отметить, что его синглтон № 3, который он пометил как "неправильный", на самом деле правильный (потому что блокировка автоматически подразумевает барьер памяти при выходе ). Он также должен быть быстрее, чем синглтон # 2, когда вы используете экземпляр более одного раза (что более или менее является точкой синглтона :-)). Итак, если вам действительно нужна ленивая одноэлементная реализация, я бы, вероятно, пошел на это - по простым причинам: (1) для всех очень ясно, что читает ваш код, что происходит, и (2) вы знаете, что произойдет за исключением.

На случай, если вам интересно: я бы никогда не использовал синглтон # 6, потому что это может легко привести к тупикам и неожиданному поведению с исключениями. Подробнее см .: режим блокировки lazy , в частности, ExecutionAndPublication.

48
atlaste