Ленивая инициализация синглтона с параметрами

Я пытаюсь создать синглтон с непустым конструктором и получить к нему синхронизированный доступ: поскольку я не могу контролировать порядок инициализации моего компонента, если компонент получает доступ к синглтону до его инициализации, он должен ждать.

Фабричный метод вызывается только один раз, и моя фаза инициализации выдает исключение

private static volatile GottwareExcelAddin _instance;   
private static readonly ManualResetEvent InitializedEvent=new ManualResetEvent(false);

    internal static Singleton CurrentInstance
    {
        get
        {
            InitializedEvent.WaitOne();
            return _instance;
        }
    }

    #endregion

    private Singleton(String url, Int otherstuff)
    {
       // do stuff
        InitializedEvent.Set();
    }


    #region public factory
    [OnWorkerThread]
    public static void Singleton(String spaceUrl, _Application excelApp)
    {
        if (_instance == null)
            _instance = new Singleton(spaceUrl, excelApp);
    }

[OnWorkerThread] — это атрибут, который запускает фабрику в рабочем потоке, и фабрика вызывается только один раз.

Когда я запускаю myapp, иногда я получаю следующее:

Источник исключения: mscorlib Тип исключения: System.Runtime.InteropServices.SEHException Сообщение об исключении: внешний компонент вызвал исключение. Целевой сайт исключения: WaitOneNative

---- Трассировка стека ---- System.Threading.WaitHandle.WaitOneNative(waitableSafeHandle As SafeHandle, миллисекундыTimeout As UInt32, hasThreadAffinity As Boolean, exitContext As Boolean) AddinExpress.RTD.2005.dll: N 00000 (0x0) Система JIT. Threading.WaitHandle.InternalWaitOne(waitableSafeHandle As SafeHandle, миллисекундыTimeout As Int64, hasThreadAffinity As Boolean, exitContext As Boolean) AddinExpress.RTD.2005.dll: N 0020 (0x14) IL System.Threading.WaitHandle.WaitOne(millisecondsTimeout As Int32, exitContext As логическое значение)

Что я делаю неправильно?


person Edmondo1984    schedule 31.03.2012    source источник


Ответы (1)


Вы не создали там правильный синглтон. Правильный синглтон должен иметь статический метод для доступа к нему и частный конструктор.

Другая проблема заключается в том, что если у вас есть параметры для инициализации синглтона, что это значит, если вы инициализируете синглтон более одного раза с разными параметрами? Это ошибка?

Предполагая, что вы можете просто игнорировать несколько инициализаций с разными параметрами, вы можете реализовать это следующим образом (но я думаю, что у вас может быть где-то ошибка проектирования):

class Singleton
{
    public static Singleton Instance(string param1, int param2)
    {
        if (_instance == null)
        {
            lock (_locker)
            {
                if (_instance == null) // Double-checked locking (works in C#!).
                {
                    _instance = new Singleton(param1, param2);
                }
            }
        }

        return _instance;
    }

    private Singleton(string param1, int param2)
    {
        // Whatever.
    }

    private static Singleton _instance;
    private static readonly object _locker = new object();
}

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

person Matthew Watson    schedule 04.04.2012
comment
Извините... Что я хочу сделать, так это инициализировать синглтон с параметрами из одной точки моего кода (при запуске). Однако из-за порядка инициализации компонентов Excel (например, если вы запускаете Excel, дважды щелкнув электронную таблицу), другие компоненты могут быть инициализированы первыми и пытаться получить доступ к синглтону. Я хочу, чтобы они дождались, пока основной компонент не инициализирует синглтон... - person Edmondo1984; 11.04.2012