8

我对流畅的界面有疑问。

我们有一些对象用作 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 选项的专用类或接口。我不确定我是否想转储.With部分,因为这会暴露对象的所有方法,而不仅仅是流利的方法。

建议和一些好的 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对象的构造和设置得当,但还是与预期的用法不兼容。

4

2 回答 2

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());

回复:建立稍后应用的状态与每次调用直接应用,如果在任何一种情况下都没有真正不可逆转的副作用,那么没关系,这取决于您的个人喜好。如果每个方法调用都提交了选项,并且您可能希望撤消该选项,那么您可能希望先建立状态,然后再应用它。如果参数对象在您应用它们时为您在属性之间进行验证,那么直接应用可能会更好,这样您就可以正确地获得验证反馈。

于 2008-10-20T10:51:37.617 回答
1

你可以有重载的方法。例如,如果它是 Substitute()。您通常不能同时拥有方法的静态版本和实例版本,但扩展方法可能会有一些用处......但是如果 Substitute 的两个版本具有不同的含义,那么简单地返回不同的类型会更清晰,所以Substitute() 的两个变体不能冲突。

于 2008-10-20T10:52:23.637 回答