Использует много статических методов плохая вещь?

Вы используете метод SPSDatabaseInfo.ExecuteScalar, отправляющий строку соединения вместо открытого SQLConnection, этот метод внутренне создает / открывает / закрывает свое собственное соединение.

Это означает, что ваши звонки выполняются в разных сеансах.

Используйте эту перегрузку метода ExecuteScalar, используя одно и то же соединение для обоих запросов

public static object ExecuteScalar(SqlConnection connection, CommandType commandType, string commandText)
{
    //pass through the call providing null for the set of SqlParameters
    return ExecuteScalar(connection, commandType, commandText, (SqlParameter[])null);
}

таким образом

using (SqlConnection cn = new SqlConnection(_connString))
{
    cn.Open();
    String.Format("EXEC sp_set_session_context N'TENANTID', '{0}'", tenantId); 
    SPSDatabaseInfo.ExecuteScalar(cn, CommandType.Text, sql);

    sql = "select SESSION_CONTEXT(N'TENANTID') AS SESSION_ID"; 
    var retVal = SPSDatabaseInfo.ExecuteScalar(cn, CommandType.Text, sql);
}
90
задан Rubens Mariuzzo 2 July 2013 в 17:46
поделиться

12 ответов

Существует два вида общих статических методов:

  • «Безопасный» статический метод всегда будет давать один и тот же вывод для одинаковых входов. Он не изменяет глобальные переменные и не вызывает никаких «небезопасных» статических методов любого класса. По сути, вы используете ограниченный вид функционального программирования - не бойтесь этого, все в порядке.
  • «Небезопасный» статический метод изменяет глобальное состояние, или прокси-серверы для глобального объекта, или некоторого другого -стабильное поведение. Это возврат к процедурному программированию, и его следует по возможности реорганизовать.

Существует несколько распространенных случаев использования «небезопасных» статик - например, в шаблоне Singleton - но имейте в виду, что, несмотря на любые красивые имена, которые вы называете их, вы просто мутируете глобальные переменные.

145
ответ дан 24 November 2019 в 07:00
поделиться

Объект без какого-либо внутреннего состояния является подозрительной вещью.

Обычно объекты инкапсулируют состояние и поведение. Объект, который только инкапсулирует поведение, является странным. Иногда это пример облегченного или летучего веса .

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

18
ответ дан 24 November 2019 в 07:00
поделиться

The other option is to add them as non-static methods on the originating object:

i.e., changing:

public class BarUtil {
    public static Foo transform(Bar toFoo) { ... }
}

into

public class Bar {
    ...
    public Foo transform() { ...}
}

however in many situations this isn't possible (e.g., regular class code generation from XSD/WSDL/etc), or it will make the class very long, and transformation methods can often be a real pain for complex objects and you just want them in their own separate class. So yeah, I have static methods in utility classes.

6
ответ дан 24 November 2019 в 07:00
поделиться

Это действительно только продолжение великого ответа Джона Милликина.


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

public class StaticClassVersionOne {
    public static void doSomeFunkyThing(int arg);
}

Который вы называете как:

StaticClassVersionOne.doSomeFunkyThing(42);

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

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

Это может быть или не быть вероятной ситуацией, но я думаю, что это стоит рассмотреть.

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

Это может быть или не быть вероятной ситуацией, но я думаю, что это стоит рассмотреть.

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

Это может быть или не быть вероятной ситуацией, но я думаю, что это стоит рассмотреть.

13
ответ дан 24 November 2019 в 07:00
поделиться

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

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

  • В некоторых языках также есть переменные уровня класса, которые позволяют инкапсулировать данные и статические методы.
4
ответ дан 24 November 2019 в 07:00
поделиться

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

А именно: Методы, которые являются «листовыми» методами (они не изменяют состояние, они просто каким-то образом преобразуют входные данные). Хорошими примерами этого являются такие вещи, как Path.Combine. Такие вещи полезны и делают для более краткого синтаксиса.

У меня проблем со статикой много:

Во-первых, если у вас есть статические классы, зависимости скрыты. Рассмотрим следующее:

public static class ResourceLoader
{
    public static void Init(string _rootPath) { ... etc. }
    public static void GetResource(string _resourceName)  { ... etc. }
    public static void Quit() { ... etc. }
}

public static class TextureManager
{
    private static Dictionary<string, Texture> m_textures;

    public static Init(IEnumerable<GraphicsFormat> _formats) 
    {
        m_textures = new Dictionary<string, Texture>();

        foreach(var graphicsFormat in _formats)
        {
              // do something to create loading classes for all 
              // supported formats or some other contrived example!
        }
    }

    public static Texture GetTexture(string _path) 
    {
        if(m_textures.ContainsKey(_path))
            return m_textures[_path];

        // How do we know that ResourceLoader is valid at this point?
        var texture = ResourceLoader.LoadResource(_path);
        m_textures.Add(_path, texture);
        return texture; 
    }

    public static Quit() { ... cleanup code }       
}

Глядя на TextureManager, вы не можете сказать, какие шаги инициализации должны быть выполнены, посмотрев на конструктор. Вы должны углубиться в класс, чтобы найти его зависимости и инициализировать вещи в правильном порядке. В этом случае требуется инициализация ResourceLoader перед запуском. Теперь увеличьте этот кошмар зависимости, и вы, вероятно, сможете догадаться, что произойдет. Представьте себе, что вы пытаетесь поддерживать код там, где нет явного порядка инициализации. Сравните это с внедрением зависимостей в экземпляры - в этом случае код не будет даже компилировать , если зависимости не выполняются!

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

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

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

Вот хорошая статья по проблемам: http://gamearchitect.net/2008/09/13/an- анатомия отчаяния менеджеров и контекстов /

5
ответ дан 24 November 2019 в 07:00
поделиться

That seems to be a reasonable approach. The reason you don't want to use too many static classes/methods is that you end up moving away from object oriented programming and more into the realm of structured programming.

In your case where you are simply transforming A to B, say all we're doing is transforming text to go from

"hello" =>(transform)=> "<b>Hello!</b>"

Then a static method would make sense.

However, if you're invoking these static methods on an object frequently and it tends to be unique for many calls (e.g. the way you use it depends on the input), or it is part of the inherent behavior of the object, it would be wise to make it part of the object and maintaining a state of it. One way to do this would be to implement it as an interface.

class Interface{
    method toHtml(){
        return transformed string (e.g. "<b>Hello!</b>")
    }

    method toConsole(){
        return transformed string (e.g. "printf Hello!")
    }
}


class Object implements Interface {
    mystring = "hello"

    //the implementations of the interface would yield the necessary 
    //functionality, and it is reusable across the board since it 
    //is an interface so... you can make it specific to the object

   method toHtml()
   method toConsole()
}

Edit: One good example of great use of static methods are html helper methods in Asp.Net MVC or Ruby. They create html elements that aren't tied to the behavior of an object, and are therefore static.

Edit 2: Changed functional programming to structured programming (for some reason I got confused), props to Torsten for pointing that out.

4
ответ дан 24 November 2019 в 07:00
поделиться

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

В любом случае, синглтон дает вам возможность позже передать что-то на заводе, чтобы получить другой экземпляр, и это меняет поведение всей вашей программы без рефакторинга. Изменение глобального класса статических методов на что-то с другими «вспомогательными» данными или немного другим поведением (дочерним классом) является основной проблемой.

И статические методы не имеют аналогичного преимущества.

Так что да,

2
ответ дан 24 November 2019 в 07:00
поделиться

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

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

3
ответ дан 24 November 2019 в 07:00
поделиться

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

2
ответ дан 24 November 2019 в 07:00
поделиться

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

1
ответ дан 24 November 2019 в 07:00
поделиться

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

1
ответ дан 24 November 2019 в 07:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: