Подтвердить что ты не робот

С# Singleton с конструктором, который принимает параметры

Я хочу создать класс static или singleton, который принимает ссылку на другой объект в своем конструкторе. Статические классы отсутствуют, но я решил, что могу создать синглтон, который принимает параметры в своем конструкторе. До сих пор мне не удавалось выяснить, что такое синтаксис. Это возможно? если да, то как мне это сделать?

Извините за отсутствие примера в начальном посте, я написал его в спешке. У меня такое ощущение, что мой ответ уже находится в ответах, но вот некоторые разъяснения того, что я хочу сделать:

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

Например, мне может понадобиться создать класс Singleton "Status", которому принадлежит объект StringBuilder и метод Draw(), который можно вызвать для записи упомянутого StringBuilder на экран. Метод Draw() должен знать о моей GraphcisDevice для рисования. Итак, что я хочу сделать это:

public class Status
{
private static Status _instance;
private StringBuilder _messages;
private GraphicsDevice _gDevice;

private Status(string message, GraphicsDevice device)
{
    _messages.Append(message);
    _gDevice = device;
}

// The following isn't thread-safe

// This constructor part is what I'm trying to figure out
public static Status Instance // (GraphicsDevice device) 
    {
    get
        {
        if (_instance == null)
            {
            _instance = new Status("Test Message!", device); 
            }
        return _instance;
        }
    }

public void UpdateMessage
...

public void Draw()
    {
    // Draw my status to the screen, using _gDevice and _messages
    }
}  

Всюду по коду я получаю свой статус Singleton и вызываю его метод UpdateMessage().

private Status _status = Status.Instance; // + pass reference to GraphicsDevice
_status.UpdateMessage("Foo!");

Затем в моем основном классе я также извлекаю синглтон и рисую его:

_status.Draw();

Да, это означает, что везде, где я получаю синглтон, мне нужно сделать это, передав ссылку на GraphicsDevice, в случае, если я впервые создам Singleton. И я мог бы использовать различные средства для получения чего-то столь же фундаментального, как GraphicsDevice в моем классе Singleton, например, зарегистрировать службу в другом месте и получить эту службу в классе Status. Этот пример очень надуманный - я пытаюсь понять, возможно ли что-то вроде этого шаблона.

4b9b3361

Ответ 1

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

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

Скажем, что у меня был SingletonFactory<T>, который позволил бы мне создать синглтон вокруг любого типа, который я передаю в factory. Это было бы очень удобно и позволило бы мне сделать что-то вроде этого:

SingletonFactory<Foo>.Instance;

Но что мешает мне сделать это:

Foo foo = new Foo();

К сожалению, похоже, что Foo больше не является ничем, поскольку я могу создать столько экземпляров, сколько хочу. Чтобы шаблон singleton работал, вам нужно иметь возможность полностью контролировать тип, экземпляры которого вам нужно ограничить. Вот почему вы не должны использовать ничего, как my SingletonFactory<T>.

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

Ответ 2

То, что вы описываете, это общий синглтон. Это выглядит так:

public class SingletonProvider <T> where T:new()
{
    SingletonProvider() {}

    public static T Instance
    {
        get { return SingletonCreator.instance; }
    }

    class SingletonCreator
    {
        static SingletonCreator() { }

        internal static readonly T instance = new T();
    }
}

http://www.codeproject.com/KB/cs/genericsingleton.aspx

Ответ 3

То, что вы конкретно просите, выглядит так:

public sealed class Singleton {
    static Singleton instance = null;
    static readonly object padlock = new Object();
    Object o;

    Singleton(Object _o) {
        o = _o;
    }

    public static Singleton Instance(Object _o) {
        lock (padlock) {
            if (instance == null) {
                instance = new Singleton(_o);
            }
            return instance;
        }
    }
}

Singleton s = Singleton.Instance(new Object());

Я подозреваю, что уже опубликованная общая версия - это то, что вы действительно хотите.

Ответ 4

Вам нужен частный конструктор, а затем метод getInstance, этот метод - это тот, кто должен получить параметр, конструктор должен быть закрытым, и он также может иметь параметры, но getInstance должен передать его, а не вы. Кстати, что вы делаете? Может показаться реальный пример.

Ответ 5

Одна вещь, которую вы можете сделать, может придерживаться выбранной вами модели singleton и просто раскрывать свойство (setter, если необходимо, добавить getter), и использовать его как  MySingleton.Instance.MyReference = new MyObject();

Если вам нужно ограничить использование вашего одноэлементного объекта, например, любые операции над объектом singleton перед установкой ссылки должны быть незаконными, вы можете иметь частный логический флаг, например, setBeenIntialized и MyReference setter установить флаг внутри. Все остальные методы будут проверять флаг в начале выполнения и вызывать исключение, если вызывается какой-либо метод, если hasBeenInitialized является ложным.

Если вам нужно иметь поведение в режиме readonly, вы можете создать исключение в сеттере MyReference, если кто-то хочет назначить другой объект, а hasBeenInitialized - true.