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 #.
У меня есть два сомнения в коде
Как можно получить доступ к внешнему классу внутри вложенного класса? Я имею в виду
internal static readonly Singleton instance = new Singleton();
Что-то называется закрытием?
Я не могу понять этот комментарий
// Explicit static constructor to tell C# compiler // not to mark type as beforefieldinit
что этот комментарий предлагает нам?
Ответы:
Нет, это не имеет ничего общего с замыканиями. Вложенный класс имеет доступ к закрытым членам своего внешнего класса, включая приватный конструктор.
Прочитайте мою статью на beforefieldinit . Вы можете или не можете хотеть статический конструктор no-op - это зависит от того, что лень гарантирует вам нужно. Вы должны знать, что .NET 4 несколько изменяет фактическую семантику инициализации типа (все еще в пределах спецификации, но ленивее, чем прежде).
Вам действительно нужен этот шаблон? Вы уверены, что не можете сойти с рук:
источник
Lazy<T>
чтобы вам не приходилось объявлять статический конструктор для магическогоBeforeFieldInit
побочного эффекта?FieldBeforeInit
этоMahaBharata
изMicrosoft
Относительно вопроса (1): ответ от Джона верен, поскольку он неявно помечает класс как «Вложенный» как закрытый, не делая его открытым или внутренним :-). Вы также можете сделать это явно, добавив «private»:
Относительно вопроса (2): в основном, что говорится в посте beforeinitfield и инициализации типов , что если у вас нет статического конструктора, среда выполнения может инициализировать его в любое время (но до его использования). Если у вас есть статический конструктор, ваш код в статическом конструкторе может инициализировать поля, что означает, что среде выполнения разрешено инициализировать поле только при запросе типа.
Поэтому, если вы не хотите, чтобы среда выполнения инициализировала поля «проактивно» перед их использованием, добавьте статический конструктор.
В любом случае, если вы реализуете синглтоны, вы хотите, чтобы он инициализировался как можно более лениво, а не тогда, когда среда выполнения думает, что должна инициализировать вашу переменную - или вам, вероятно, просто все равно. От вашего вопроса, я полагаю, вы хотите их как можно позже.
Это приводит к встрече Джона о синглтоне , который является основной темой этого вопроса. Ох и сомнения :-)
Я хотел бы отметить, что его синглтон № 3, который он пометил как «неправильный», на самом деле правильный (потому что блокировка автоматически подразумевает барьер памяти при выходе ). Он также должен быть быстрее, чем синглтон # 2, когда вы используете экземпляр более одного раза (что более или менее является точкой синглтона :-)). Так что, если вам действительно нужна ленивая одноэлементная реализация, я бы, вероятно, пошел на это - по тем простым причинам, что (1) всем ясно, что читает ваш код, что происходит, и (2) вы знаете, что произойдет за исключением
Если вам интересно: я бы никогда не использовал синглтон # 6, потому что это может легко привести к тупикам и неожиданному поведению с исключениями. Для получения дополнительной информации см .: режим блокировки lazy , в частности, ExecutionAndPublication.
источник
Regarding question (1): The answer from Jon is correct ...
Джон Скит всегда прав ....