C# 中的流畅接口

发布于 2024-07-07 04:51:04 字数 3145 浏览 8 评论 0原文

我有一个关于流畅界面的问题。

我们有一些对象用作 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 部分,因为这会公开对象的所有方法,而不仅仅是 流畅 的方法。

建议和一些好的网址将是最受欢迎的,我已经搜索了许多示例,但它们倾向于显示这样的示例:(

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 对象被正确构造和设置,但它与预期用途不兼容。

I have a question with fluent interfaces.

We have some objects that are used as parameter objects for a SQL interface, here's an example:

using (DatabaseCommand cmd = conn.CreateCommand(
    "SELECT A, B, C FROM tablename WHERE ID = :ID",
    SqlParameter.Int32(":ID", 1234)))
{
    ...
}

For some of these parameters, I'd like to enable some specialized options, but instead of adding more properties to the Int32 method (which is just one of many), I thought I'd look into fluent interfaces.

Here's an example where I've added what I am looking into:

SqlParameter.Int32(":ID", 1234).With(SqlParameterOption
    .Substitute
    .Precision(15)
)

I know these two options doesn't make sense for this type of parameter, but that's not what the question is about.

In the above case, Substitute would have to be a static property (or method if I just add some parenthesis) on the SqlParameterOption class, whereas Precision would have to be an instance method.

What if I reorder them?

SqlParameter.Int32(":ID", 1234).With(SqlParameterOption
    .Precision(15)
    .Substitute
)

Then Substitute would have to be the instance property and Precision the static method. This won't compile of course, I can't have both a static and a non-static property or method with the same name.

How do I do this? Am I completely on the wrong track here?

While re-reading the question, I had an idea, would this different syntax below make more sense?

SqlParameter.Int32(":ID", 1234).With
    .Precision(15)
    .Substitute

In this case both would be instance methods on whatever With returns, which would be a specialized class or interface for SqlParameter options like this. I'm not sure I'd like to dump the .With part, as this would expose all methods of the object, instead of just the fluent ones.

Advice and some good url's would be most welcome, I've scoured over many examples, but they tend to show examples like this:

order
    .AddFreeShipping()
    .IncludeItem(15)
        .SuppressTax();

(lifted from this page)


Edit: Followup after responses
From @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 this approach, With would have to take the object, and apply it to the parameter. I'm fine with that.

If I used the syntax I added as an example, it would be like this:

SqlParameter.Int32(":ID", 1234).With
                               .Precision(15)
                               .Substitute());

In this case, With wouldn't know when the chain ended, so each option would have to apply its effect directly.

What is preferred? That the options build up an effect object that will have to be applied later, or that each effect applies its effect directly?

My decision:
As @marxidad says, if the changes are irreversible, and could potentially be subject to a reversal, building up state and failing at some point with an exception is the way I'll go.

However, in this case, I'm going with a simpler approach that modifies the SqlParameter object directly.

In this case, my code will look like this:

SqlParameter.Int32(":ID", 1234).With
                               .Precision(15)
                               .Substitute());

Edit: Gah, that's how it goes when I focus on just one thing.

I can't use that syntax, I'll go with the following, as suggested by @marxidad:

SqlParameter.Int32(":ID", 1234).With(new SqlParameterOption()
                                           .Precision(15)
                                           .Substitute());

The reason is of course that the method that takes the SqlParameter object as an argument is unable to cope with the object returned by With, so although the SqlParameter object is constructed and set up properly, it became incompatible with the intended usage.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

以歌曲疗慰 2024-07-14 04:51:04

SqlParameterOption 的 方法都可以是返回同一对象的实例方法:

class SqlParameterOption
 {
    public SqlParameterOption Precision(int p) {/* ... */; return this;}
    public SqlParameterOption Substitute() {/* ... */; return this;}
    /* ... */       
 }

/* ... */
SqlParameter.Int32(":ID", 1234).With(new SqlParameterOption()
                                           .Precision(15)
                                           .Substitute());

回复:构建稍后应用的状态与直接在每次调用中应用(如果没有真正不可逆转的方面) - 无论哪种情况,效果都没关系,这取决于你的个人喜好。 如果选项是在每次方法调用时提交的,并且您可能想要撤消该操作,那么您可能需要首先构建状态,然后应用它。 如果参数对象在您应用属性时为您在属性之间进行验证,那么最好直接应用,这样您就能以正确的方式获得验证反馈。

SqlParameterOption's methods can all be instance methods that returns the same object:

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: building up state to be applied later vs. applying directly with each call, if there's no real irreverisible side-effects in either case, then it doesn't matter and it's up to your personal taste. If the options are commited with each method call and there's a chance you might want to undo that, then you might want to build up the state first and then apply it. If the parameter object does validation between properties for you as you apply them then it might be better to go with direct application so you'll get validation feedback right way.

甜心 2024-07-14 04:51:04

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

You can have overloaded methods though. For example, if it was Substitute(). You can't normally have both static and instance versions of a method, but extension methods might be of some use... but if the two versions of Substitute have different meanings, it would be cleaner to simply have different types being returned, so that the two variants of Substitute() can't conflict.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文