У меня вопрос с плавными интерфейсами.
У нас есть несколько объектов, которые используются в качестве объектов параметров для интерфейса SQL, вот пример:
using (DatabaseCommand cmd = conn.CreateCommand(
"SELECT A, B, C FROM tablename WHERE ID = :ID",
SqlParameter.Int32(":ID", 1234)))
{
...
}
Для некоторых из этих параметров я хотел бы включить некоторые специализированные параметры, но вместо добавления дополнительных свойств к методу Int32 (который является лишь одним из многих), я подумал, что займусь плавными интерфейсами.
Вот пример, в котором я добавил то, что ищу:
SqlParameter.Int32(":ID", 1234).With(SqlParameterOption
.Substitute
.Precision(15)
)
Я знаю, что эти два варианта не имеют смысла для этого типа параметра, но вопрос не в этом.
В приведенном выше случае Substitute должен быть статическим свойством (или методом, если я просто добавлю скобки) в классе SqlParameterOption, тогда как Precision должен быть методом экземпляра.
Что, если я их переупорядочу?
SqlParameter.Int32(":ID", 1234).With(SqlParameterOption
.Precision(15)
.Substitute
)
Тогда Substitute должен быть свойством экземпляра, а Precision - статическим методом. Это, конечно, не будет компилироваться, у меня не может быть как статического, так и нестатического свойства или метода с тем же именем.
Как мне это сделать? Я здесь совершенно ошибаюсь?
При перечитывании вопроса у меня возникла идея, будет ли этот другой синтаксис ниже иметь больше смысла?
SqlParameter.Int32(":ID", 1234).With
.Precision(15)
.Substitute
В этом случае оба будут методами экземпляра для всего, что возвращает With, который будет специализированным классом или интерфейсом для таких параметров SqlParameter. Я не уверен, что хотел бы сбросить часть .С, так как это откроет все методы объекта, а не только беглый.
Совет и несколько хороших URL-адресов были бы очень кстати, я просмотрел много примеров, но они, как правило, показывают такие примеры:
order
.AddFreeShipping()
.IncludeItem(15)
.SuppressTax();
(снято с эта страница)
Редактировать: Последующие действия после ответов От @marxidad:
class SqlParameterOption
{
public SqlParameterOption Precision(int p) {/* ... */; return this;}
public SqlParameterOption Substitute() {/* ... */; return this;}
/* ... */
}
/* ... */
SqlParameter.Int32(":ID", 1234).With(new SqlParameterOption()
.Precision(15)
.Substitute());
При таком подходе With потребуется взять объект и применить его к параметру. Меня это устраивает.
Если бы я использовал синтаксис, который добавил в качестве примера, это было бы так:
SqlParameter.Int32(":ID", 1234).With
.Precision(15)
.Substitute());
В этом случае With не будет знать, когда цепочка закончилась, поэтому каждая опция должна будет применить свой эффект напрямую.
Что предпочтительнее? Что параметры создают объект эффекта, который нужно будет применить позже, или что каждый эффект применяет свой эффект напрямую?
Мое решение: Как говорит @marxidad, если изменения необратимы и потенциально могут быть отменены, я пойду по пути создания состояния и сбоя в какой-то момент с исключением.
Однако в этом случае я выберу более простой подход, который напрямую изменяет объект SqlParameter.
В этом случае мой код будет выглядеть так:
SqlParameter.Int32(":ID", 1234).With
.Precision(15)
.Substitute());
Редактировать: Угу, вот как бывает, когда я сосредотачиваюсь только на одном.
Я не могу использовать этот синтаксис, я воспользуюсь следующим, как предлагает @marxidad:
SqlParameter.Int32(":ID", 1234).With(new SqlParameterOption()
.Precision(15)
.Substitute());
Причина, конечно, в том, что метод, который принимает объект SqlParameter в качестве аргумента, не может справиться с объектом, возвращаемым With, поэтому, хотя объект SqlParameter сконструирован и настроен правильно, он стал несовместим с предполагаемым использованием.





Все методы SqlParameterOption's могут быть методами экземпляра, возвращающими один и тот же объект:
class SqlParameterOption
{
public SqlParameterOption Precision(int p) {/* ... */; return this;}
public SqlParameterOption Substitute() {/* ... */; return this;}
/* ... */
}
/* ... */
SqlParameter.Int32(":ID", 1234).With(new SqlParameterOption()
.Precision(15)
.Substitute());
Re: создание состояния для последующего применения по сравнению с применением напрямую при каждом вызове, если в любом случае нет реальных необратимых побочных эффектов, это не имеет значения, и это зависит от вашего личного вкуса. Если параметры фиксируются при каждом вызове метода и есть вероятность, что вы захотите отменить это, тогда вы можете сначала создать состояние, а затем применить его. Если объект параметра выполняет за вас проверку свойств по мере их применения, то, возможно, лучше использовать прямое приложение, чтобы вы получили правильную обратную связь с проверкой.
Однако вы можете перегрузить методы. Например, если это был Substitute (). Обычно у вас не может быть как статической, так и экземпляра версии метода, но методы расширения могут быть полезны ... но если две версии Substitute имеют разные значения, было бы проще просто возвращать разные типы, поэтому что два варианта Substitute () не могут конфликтовать.
В этом случае не было бы конфликта по поводу смысла, вопрос был больше о том, как я организую код, чтобы получить то, что я хочу, с точки зрения синтаксиса. Как показал marxidad, создание экземпляра объекта option решает эту проблему.