Свободные интерфейсы в C#
У меня вопрос с беглыми интерфейсами.
У нас есть некоторые объекты, которые используются в качестве объектов параметров для интерфейса 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)
)
Я знаю, что эти два параметра не имеют смысла для этого типа параметра, но вопрос не в этом.
В приведенном выше случае замена должна быть статическим свойством (или методом, если я просто добавлю несколько скобок) в классе SqlParameterOption, тогда как Precision должен быть методом экземпляра.
Что если я переупорядочу их?
SqlParameter.Int32(":ID", 1234).With(SqlParameterOption
.Precision(15)
.Substitute
)
Тогда заменитель должен быть свойством экземпляра, а Precision - статическим методом. Конечно, это не скомпилируется, я не могу иметь как статическое, так и нестатическое свойство или метод с одинаковым именем.
Как мне это сделать? Я совершенно не на том пути?
Перечитывая вопрос, у меня возникла идея, будет ли этот другой синтаксис ниже более понятным?
SqlParameter.Int32(":ID", 1234).With
.Precision(15)
.Substitute
В этом случае оба будут методами экземпляра для любого возврата С, который будет специализированным классом или интерфейсом для таких параметров SqlParameter, как этот. Я не уверен, что хотел бы сбросить часть .With, так как это раскрыло бы все методы объекта, а не только беглые.
Советы и несколько хороших URL-адресов были бы очень кстати, я просмотрел много примеров, но они, как правило, показывают примеры, подобные этому:
order
.AddFreeShipping()
.IncludeItem(15)
.SuppressTax();
(снято с этой страницы)
Изменить: продолжение после ответов от Mark Cidade:
class SqlParameterOption
{
public SqlParameterOption Precision(int p) {/* ... */; return this;}
public SqlParameterOption Substitute() {/* ... */; return this;}
/* ... */
}
/* ... */
SqlParameter.Int32(":ID", 1234).With(new SqlParameterOption()
.Precision(15)
.Substitute());
При таком подходе С должен был бы взять объект и применить его к параметру. Я в порядке с этим.
Если бы я использовал синтаксис, который я добавил в качестве примера, это было бы так:
SqlParameter.Int32(":ID", 1234).With
.Precision(15)
.Substitute());
В этом случае With не будет знать, когда закончится цепочка, поэтому каждый параметр должен будет применить свой эффект напрямую.
Что является предпочтительным? Что опции создают объект эффекта, который нужно будет применить позже, или что каждый эффект применяет свой эффект напрямую?
Мое решение: как говорит Mark Cidade, если изменения необратимы и потенциально могут быть подвержены аннулированию, создание состояния и сбой в какой-то момент, за исключением, - это путь, по которому я буду идти.
Однако в этом случае я использую более простой подход, который напрямую изменяет объект SqlParameter.
В этом случае мой код будет выглядеть так:
SqlParameter.Int32(":ID", 1234).With
.Precision(15)
.Substitute());
Редактировать: Га, вот как это происходит, когда я сосредоточен только на одной вещи.
Я не могу использовать этот синтаксис, я пойду со следующим, как предложено Mark Cidade:
SqlParameter.Int32(":ID", 1234).With(new SqlParameterOption()
.Precision(15)
.Substitute());
Причина, конечно, в том, что метод, который принимает объект SqlParameter в качестве аргумента, не может справиться с объектом, возвращаемым функцией With, поэтому, хотя объект SqlParameter создан и настроен правильно, он стал несовместим с предполагаемым использованием.
2 ответа
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 () не могут конфликтовать.