2010-05-20 3 views
7

Я хотел бы узнать ваше мнение о стиле кодирования, о котором я нахожусь на заборе. Я понимаю, что, вероятно, нет окончательного ответа, но я хотел бы видеть, есть ли сильное предпочтение в том или ином направлении.Вопрос о стиле/удобочитаемости в отношении оператора C# «using»

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

{ 
    log = new log(); 
    log.SomeProperty = something; // several of these 
    log.Connection = new OracleConnection("..."); 
    log.InsertData(); // this is where log.Connection will be used 
    ... // do other stuff with log, but connection won't be used again 
} 

где log.Connection является OracleConnection, который реализует IDisposable.

neatnik во мне хочет изменить его на:

{ 
    using (OracleConnection connection = new OracleConnection("...")) 
    { 
     log = new log(); 
     log.SomeProperty = something; 
     log.Connection = conn; 
     log.InsertData(); 
     ... 
    } 
} 

Но любитель краткости и получить без отрыва от работы сделано, слегка быстрее хочет сделать:

{ 
    log = new log(); 
    log.SomeProperty = something; 
    using (log.Connection = new OracleConnection("...")) 
     log.InsertData(); 
    ... 
} 

Для по какой-то причине я чувствую себя немного грязно, делая это. Считаете ли вы это плохо или нет? Если вы считаете, что это плохо, почему? Если это хорошо, почему?

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

ответ

2

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

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

Также обратите внимание, что вы можете выполнить другую инициализацию вне блока using. Здесь это не имеет значения, но может иметь значение, если вы «используете» какой-то действительно дорогой ресурс. То есть:

log = new log(); 
log.SomeProperty = something; // This can be outside the "using" 
using (OracleConnection connection = new OracleConnection("...")) 
{ 
    log.Connection = conn; 
    log.InsertData(); 
    ... 
} 
+1

Благодарим вас за обращение к актуальному вопросу. Ваш вопрос о выполнении инициализации вне блока использования интересен, потому что единственная причина, по которой я переместил его внутри блока, состоял в том, что я чувствовал, что было более аккуратным, чтобы связать все связанные коды. Я не думал о потенциальном расходе (не проблема здесь, а действительный момент, чтобы иметь в виду). –

2

Я бы прослушал неатик в вас. Мне нравится его путь лучше лично.

+0

-1 ... но почему? –

+0

Потому что второй способ выглядел очень уродливо для меня, и я очень подробно расскажу о том, как код «выглядит». – Josh

+0

Хорошо, добро, честно. –

4

Они оба ужасные. Ни одного из них.

Вы делаете то, что я называю «high maintenance class» здесь. В классе высокого обслуживания есть контракт, в котором говорится: «Я требую, чтобы вы дали мне кучу ресурсов, и вам нужно знать, когда я с ними поработаю, и тщательно их очистить». Этот контракт означает, что пользователь класса должен знать, как реализуется класс, тем самым нарушая принцип инкапсуляции и абстракции, который мотивировал создание класса в первую очередь.

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

Некоторые способы сделать это лучше:

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

2) make InsertData принимает соединение в качестве параметра. Вызывающий абонент все еще может нести ответственность за очистку соединения, потому что регистратор не удерживает его.

3) сделать третий класс «вставкой», который является одноразовым и берет журнал и соединение в его конструкторе. Вставка устанавливает соединение, когда оно расположено; тогда вызывающий абонент несет ответственность за удаление вставки.

+1

Это интересно, потому что эмпирическое правило большую часть времени я обнаружил как «Если вы его создадите, это ваша задача избавиться от него». Я был бы более удивлен, увидев, что регистратор удаляет соединение, которое может или не может быть использовано другими регистраторами. Например, прошло некоторое время с тех пор, как я использовал SqlCommand напрямую, но, если я помню, он не передает соединение, которое вы ему передаете. – Josh

+0

@Josh: Если вы хотите поделиться, сделайте вариант №2. Соединение просто не должно быть членом журнала. –

+0

@Josh: Сравните это с потоковыми читателями, которые владеют распоряжением потоком, который они читают. Важно то, что контракт не был (1) сложным или (2) неожиданным. Я был бы удивлен, обнаружив, что регистратор держался за ссылку на собранную коллекцию; откуда я знаю, что журнал работает с ним? –

0

Если log реализует IDisposable, то сделайте второй выбор, поскольку фигурные скобки явны.В некоторых случаях вы можете использовать несколько using заявления:

using (Graphics g = ...) 
using (Pen p = new Pen ...) 
using (Font f = new Font ...) 
{ 



} 

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

+0

Журнал не реализует IDisposable. Имея это в виду, предпочитаете ли вы «опрятный» первый выбор? –

+0

Затем пойдите с предложениями Эрика Липперта. Он в значительной степени - это рот лошади в этой области. –

+1

Предложения Эрика были бы замечательными, если бы я был тем, кто разрабатывал классы, используя связь, но он не предлагал ничего, что касалось моего фактического вопроса. –

1

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

+1

Согласен, этот пример показывает плохой интерфейс, но давайте оставим его в стороне. Я понимаю, что два способа эквивалентны, но у вас есть предпочтение кишки в любом случае? –

+0

@Charles: Моя кишка говорит мне, что причина, по которой вы сталкиваетесь с этой дилеммой, - это плохой выбор оригинального дизайна (что делает соединение членом). Если вы действительно не можете отменить этот выбор, я бы все равно ни к чему.Я бы сделал что-то близкое к # 1, но я бы поместил объект журнала полностью в область используемого блока, чтобы вы не могли использовать его после того, как соединение установлено. –

+1

Да, реальность быть программистом в прокате - это то, что вы ежедневно сталкиваетесь с этой дилеммой, а чаще всего не можете исправить основной вопрос. Это факт, что я регулярно вижу, что явно опытные разработчики на SO не понимают. Хорошая мысль заключается в том, что вы перемещаете всю ссылку на объект, связанный с подключением, внутри блока использования, чтобы предотвратить возможность его использования соединения после его утилизации. Спасибо за ваш вклад. –

Смежные вопросы