Можно использовать синглтон с конструктором не по умолчанию в C #? - PullRequest
6 голосов
/ 04 апреля 2011

Это небольшая разница в этом вопросе: Можно использовать синглтон с конструктором не по умолчанию в C #?

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

Мое решение (которое не изящно) для этого - использовать статический метод CreateInstance(), который принимает параметры и создает экземпляр singleton. Тогда у меня был бы другой статический метод GetInstance(), который был бы без параметров для получения экземпляра синглтона. В коде мне нужно было бы обеспечить логические вызовы CreateInstance перед любыми вызовами GetInstance. Однако я не могу применить это во время компиляции. Однако я могу проверить во время выполнения, выдав исключение в GetInstance, если оно вызывается до CreateInstance.

Могу ли я в любом случае добиться такого поведения с помощью принудительного времени компиляции? Или, по крайней мере, есть ли лучший способ сделать то же самое?

Ответы [ 6 ]

5 голосов
/ 04 апреля 2011

Нет способа сделать это во время компиляции, потому что это все равно, что спросить компилятор: «Можете ли вы доказать, что код X никогда не выполняется до выполнения кода Y в присутствии нескольких потоков?».Это невозможно сделать.

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

Вы можете сделать его немного лучше, выставив Func<SingletonType>собственность в вашем классе синглтон.Когда кто-то запрашивает экземпляр синглтона, а экземпляр еще не создан, ваш класс вызывает этот «фабричный метод» для создания синглтона.Если фабричный метод - null, то вы либо генерируете исключение, либо (если применимо) конструкцию, используя некоторые параметры по умолчанию.

То, что это делает, по существу откладывает построение синглтона до тех пор, пока оно фактически не потребуется для первоговремя, так что это некоторое улучшение.Но основной принцип тот же.

Обновление:

Как указывает LukeH, это в значительной степени то, что делает Lazy<T> (только .NET 4),Если возможно, используйте его вместо того, чтобы писать свой.

1 голос
/ 04 апреля 2011

В классическом синглтоне настоящая магия происходит в static readonly, который создает экземпляр сразу после его использования:

public class MySingleton
{
    private static readonly _instance = new MySingleton();

    private MySingleton() {}

    public static MySingleton Instance
    {
        get
        {
            return _instance;
        }
    }

}

Если у вас есть параметры для передачи конструктору, вы должны реализовать блокировку самостоятельно (обратите внимание на двойное if переключение lock):

public class MySingletonWithConstructor
{
    private static _instance;
    private static object _lock = new Object();

    private MySingletonWithConstructor(string myArg) 
    {
        // ... do whatever necessary
    }

    public static MySingletonWithConstructor Instance
    {
        get
        {
            if(_instance==null)
            {
                lock(_lock)
                {
                    if(_instance==null) // double if to prevent race condition
                    {
                        _instance = new MySingletonWithConstructor("Something");
                    }
                }
            }
            return _instance;
        }
    }

}
0 голосов
/ 04 апреля 2011

Используйте CreateInstance (), чтобы быть загрузчиком Lazy<T>, и пусть GetInstance возвращает Lazy.Value (вы можете создать статическое поле только для чтения, для которого установлено значение = thelazy.Value, чтобы обеспечить единственную запись в CreateInstance ))

0 голосов
/ 04 апреля 2011

В вашем методе GetInstance() почему бы вам просто не вызвать CreateInstance, если ваше значение равно нулю, тогда у вас ленивая инициализация ..

0 голосов
/ 04 апреля 2011

Я бы сделал это похоже на это.Возможно, вам придется добавить блокировки или другие вещи для обеспечения:

 public class ClassA {     
    private static ClassA instance;

    private int param;

    private ClassA(int param) {
       this.param = param;
    }

    public static ClassA getInstance() {
       if (instance == null) {
          throw new CustomException("Not yet initialised");
       } else {
          return instance;
       }
    }

    public static void createInstance(int param) {
       if (instance == null) {
          instance = new ClassA(param);
       }
    }
}
0 голосов
/ 04 апреля 2011

Вы можете просто GetInstance() вызвать метод CreateInstance(), если одноэлементный объект еще не существует.

...