Это плохая практика иметь состояние в статическом классе? - PullRequest
11 голосов
/ 02 мая 2010

Я хотел бы сделать что-то вроде этого:

public class Foo {
    // Probably really a Guid, but I'm using a string here for simplicity's sake.
    string Id { get; set; }

    int Data { get; set; }

    public Foo (int data) {
        ...
    }

    ...
}

public static class FooManager {
    Dictionary<string, Foo> foos = new Dictionary<string, Foo> ();

    public static Foo Get (string id) {
        return foos [id];
    }

    public static Foo Add (int data) {
        Foo foo = new Foo (data);
        foos.Add (foo.Id, foo);

        return foo;
    }

    public static bool Remove (string id) {
        return foos.Remove (id);
    }

    ...

    // Other members, perhaps events for when Foos are added or removed, etc.
}

Это позволило бы мне управлять глобальной коллекцией Foo с где угодно. Однако мне сказали, что статические классы всегда должны быть без сохранения состояния - вы не должны использовать их для хранения глобальных данных. Глобальные данные в целом, похоже, осуждаются. Если я не должен использовать статический класс, как правильно решить эту проблему?

Примечание: я нашел похожий вопрос , но ответ, который я получил, на самом деле не применим в моем случае.

Ответы [ 7 ]

9 голосов
/ 02 мая 2010

Кто считает, что статические классы должны быть без состояний? Статический означает заявлено.

Просто знайте, как статические классы работают в CLR:

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

Также следует помнить о проблемах параллелизма.

Как примечание: меня удивляет, как часто люди говорят: «Не используйте X». Это похоже на то, как кто-то входит в ваш инструментарий и указывает на полдюжины инструментов и говорит: «Эти инструменты - плохая практика» Это не имеет смысла.

4 голосов
/ 02 мая 2010

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

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

Например, вы можете сравнить, как app.config и web.config используются в .NET Framework. Доступ к ним осуществляется через статический класс System.Configuration.ConfigurationManager со статическим свойством AppSettings , который скрывает подробности о том, как достичь глобальных данных.

3 голосов
/ 02 мая 2010

То, что вы здесь ищете, это одноэлементный класс, а не статический класс.Статические классы и методы должны быть переданы для процедур без сохранения состояния.Одиночный класс создается один раз и только один раз за запуск приложения и имеет полную функциональность класса как такового.Каждый раз, когда вы будете ссылаться на него в будущем, вы будете возвращать точно такой же экземпляр с точно такими же свойствами члена.

Первый результат Google для "C # singleton", по-видимому, имеет довольно приличное объяснение реализации.http://www.yoda.arachsys.com/csharp/singleton.html

2 голосов
/ 02 мая 2010

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

Но рекомендуется следить за безопасностью потоков.

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


private static readonly object LockStaticFields = new object();

public static Foo Add (int data) {
        lock(LockStaticFields)
        {
           Foo foo = new Foo (data);
           foos.Add (foo.Id, foo);

           return foo;
        }
    }

0 голосов
/ 02 мая 2010

Еще одна вещь, которую следует принять во внимание, это само приложение и бюджет для него. Действительно ли нужно что-то более сложное, чем статический класс?

0 голосов
/ 02 мая 2010

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

0 голосов
/ 02 мая 2010

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

...