我有一个流畅的界面问题。
我们有一些对象用作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
)
然后替换必须是实例属性而精确静态方法。这当然不会编译,我不能同时拥有静态和非静态属性或同名方法。
我该怎么做?我完全走错了吗?
在重读这个问题时,我有一个想法,下面这个不同的语法会更有意义吗?
SqlParameter.Int32(":ID", 1234).With
.Precision(15)
.Substitute
在这种情况下,两者都是返回的实例方法,这将是SqlParameter选项的专用类或接口,如下所示。我不确定是否要转储 .With 部分,因为这会暴露对象的所有方法,而不仅仅是流利的。
建议和一些好的网址将是最受欢迎的,我已经仔细研究了很多例子,但他们倾向于展示这样的例子:
order
.AddFreeShipping()
.IncludeItem(15)
.SuppressTax();
(取自this page)
修改:在回复后进行跟进 来自@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());
编辑: Gah,当我专注于一件事时,就是这样。
我无法使用该语法,我会按照@marxidad的建议使用以下内容:
SqlParameter.Int32(":ID", 1234).With(new SqlParameterOption()
.Precision(15)
.Substitute());
原因当然是将SqlParameter对象作为参数的方法无法处理With返回的对象,因此尽管构造并正确设置了SqlParameter对象,但它与预期用法不兼容。
答案 0 :(得分:8)
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:建立状态以便稍后应用而不是直接应用每次调用,如果在任何一种情况下都没有真正不可避免的副作用,那么这无关紧要,这取决于你的个人品味。如果选项与每个方法调用一起提交,并且您可能想要撤消该选项,那么您可能希望首先构建状态然后应用它。如果参数对象在您应用它们时对属性进行验证,那么最好使用直接应用程序,这样您就可以正确地获得验证反馈。
答案 1 :(得分:1)
您可以重载方法。例如,如果是Substitute()。您通常不能同时拥有方法的静态版本和实例版本,但扩展方法可能有一些用处...但如果两个版本的替换具有不同的含义,那么简单地返回不同的类型会更简洁,所以Substitute()的两个变体不能冲突。