在 C# 3 中编写流畅接口的技巧

发布于 2024-07-07 21:13:14 字数 324 浏览 13 评论 0 原文

我正在寻找一些有关 C# 流畅界面的好技巧。 我自己只是在学习,但很想听听我正在阅读的文章之外的其他人的想法。 我特别想知道:

  1. 什么时候流利太多了?
  2. 有流畅的模式吗?
  3. C# 中的什么使流利接口更加流利(例如扩展方法),
  4. 复杂的流利接口仍然是流利接口吗?
  5. 重构以获得流畅的界面或重构现有的流畅界面
  6. 您曾经使用过或可以推荐任何好的例子吗?

如果您可以在每个帖子中发布一个提示或想法,或者其他任何内容。 我也想看看他们是如何投票的。

先感谢您。

I'm after some good tips for fluent interfaces in C#. I'm just learning about it myself but keen to hear what others think outside of the articles I am reading. In particular I'm after:

  1. when is fluent too much?
  2. are there any fluent patterns?
  3. what is in C# that makes fluent interfaces more fluent (e.g. extension methods)
  4. is a complex fluent interface still a fluent one?
  5. refactoring to arrive at a fluent interface or refactoring an existing fluent interface
  6. any good examples out there that you have worked with or could recommend?

If you could post one tip or thought, or whatever per post. I want to see how they get voted on, too.

Thank you in advance.

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

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

发布评论

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

评论(8

莳間冲淡了誓言ζ 2024-07-14 21:13:14

作为流畅界面的消费者,我所经历的最大挑战是,它们中的大多数并不是真正的流畅界面——相反,它们实际上是我所说的“清晰界面”的实例。

流畅的界面意味着其主要目标是使其易于说出,而清晰的界面则意味着其主要目标是易于阅读。 大多数流畅的界面往往难以编码,但相反,其他人以后却非常容易阅读。

Assert().That().This(actual).Is().Equal().To(expected).
    Except().If(x => x.GreaterThan(10));

...以后阅读比实际编写代码要容易得多!

The single biggest challenge I have experienced as a consumer of fluent interfaces is that most of them aren't really fluent intefaces -- instead they are really instances of what I tend to refer to as 'legible interfaces'.

A fluent interface implies that its primary goal is to make it easy to SPEAK it whereas a legible interface implies that its primary goal is to be easy to READ it. Most fluent interfaces only tend to be ridiculously difficult to code with but conversely incredibly easy to READ later by others.

Assert().That().This(actual).Is().Equal().To(expected).
    Except().If(x => x.GreaterThan(10));

...is alot easier to read later than it is to actually compose in code!

小傻瓜 2024-07-14 21:13:14

关于你的第四点;

是的,我认为复杂的流畅界面仍然可以流畅。

我认为流畅的界面在某种程度上是一种妥协。 (虽然很好!)对于使用自然语言进行编程已经有很多研究,并且通常自然语言不足以精确地表达程序。

流畅的界面被构建为像编程语言一样编写,只允许用自然语言表达的一小部分内容,但它们读起来像自然语言。

例如,如果你看一下犀牛模拟,那么与普通库相比,编写部分就很复杂。 我花了更长的时间来学习,主要是因为流畅的界面,但它使代码更容易阅读。 因为程序通常只编写一次并多次读取,这是一个很好的权衡。

因此,稍微限定一下我的观点。 编写复杂但易于阅读的流畅界面仍然可以流畅。

On your 4th point;

Yes I think that a complex fluent interface can still be fluent.

I think fluent interfaces are somewhat of a compromise. (although a good one!) There has been much research into using natural language for programming and generally natural language isn't precise enough to express programs.

Fluent interfaces are constructed so that they write like a programming language, only a small subset of what you can express in a natural language is allowed, but they read like a natural language.

If you look at rhino mocks for example the writing part has been complicated compared to a normal library. I took me longer to learn mostly due to the fluent interface but it makes code a lot easier to read. Because programs are usually written once and read a lot more than once this is a good tradeoff.

So to qualify my point a bit. A fluent interface that's complex to write but easy to read can still be fluent.

安静 2024-07-14 21:13:14

当使用继承和流畅的接口时,您会遇到麻烦,因为使用多态方法会破坏您的调用链,并且您绝对不希望通过在不需要的地方使用丑陋的转换和括号来使您的接口变得不流畅。
我写了一篇关于模式的文章,为您提供了使用通用构建器和具有通用约束的通用扩展方法的解决方法:
http://liviutrifoi.wordpress.com /2009/02/16/fluence-interfaces-constraints-at-compile-time/

You'll hit a brick when using inheritance along with fluent interfaces because using polymorphic methods break your call chains and you definitely don't want to make your interfaces non-fluent by using ugly casting and paranthesis where they are not needed.
I've written an article about a pattern that provides you with a workaround using generic builders and generic extension methods with generic constraints:
http://liviutrifoi.wordpress.com/2009/02/16/fluent-interfaces-constraints-at-compile-time/

岛徒 2024-07-14 21:13:14

Moq 隐藏了不相关的方法,例如 equals、ToString 等,使其流畅的界面更易于使用。

隐藏系统对象是一篇解释这样做的好处。

Moq hides unreleated methods such as equals, ToString and so on to make their fluent interface even easier to use.

Hiding System Object is an article explaining the benefit of doing this.

鱼忆七猫命九 2024-07-14 21:13:14

关于你的第二个问题和第三个问题;

我注意到的三种流畅模式

第一个使用 using 语句(C# 2.0)在特定上下文中运行代码,例如:

using(var transaction = new Transaction())
{
  // ..
  // ..
}

它使用 Transaction 的构造函数和处理程序来设置事务,然后在此上下文中运行代码。

第二个的作用几乎相同,但是对于 lambda,这在 Rhino Mocks 中被大量使用。

(new Transaction()).Run( () => mycode(); );

最著名的流畅接口是使用返回类型来链接方法调用。 大多数方法都会返回此值,以便您可以对同一对象进行链接调用。 但您也可以返回不同的对象来根据调用的方法更改上下文。 如果您有一个只能在事务中运行的对象(抱歉无法想到不同的示例),您可以给它一个 StartTransaction 方法,该方法返回一个初始化的事务,您可以在其中运行 call run 和 stoptransaction,用伪代码

class Runner
{
  Transaction StartTransaction()
  {
    return new Transaction(this);
  }
}

class Transaction
{
  Transaction Run()
  Transaction StopTransaction()
}

:调用看起来像

var runner = new Runner();
runner
  .StartTransaction()
  .Run()
  .StopTransaction();

当然,您需要添加各种错误处理等。

And on your 2nd and 3rd question;

Three fluent patterns i've noticed

The first uses the using statement (C# 2.0) to run code in a certain context for example:

using(var transaction = new Transaction())
{
  // ..
  // ..
}

This uses the constructor and disposer of Transaction to set up a transaction and then runs the code in this context.

The second does almost the same but with lambda's, this is used a lot in Rhino Mocks for example.

(new Transaction()).Run( () => mycode(); );

The best known fluent interface is to use return types to chain method calls. Mostly methods return this so you can chain calls on the same object. But you can also return different objects to change the context depending on the method called. If you've got an object that can only run in a transaction (sorry can't think of a different example) you can give it a StartTransaction method that returns an initialized transaction where you can run call run and stoptransaction, in pseudocode:

class Runner
{
  Transaction StartTransaction()
  {
    return new Transaction(this);
  }
}

class Transaction
{
  Transaction Run()
  Transaction StopTransaction()
}

where the call looks like

var runner = new Runner();
runner
  .StartTransaction()
  .Run()
  .StopTransaction();

Of course you need to add all kinds of error handling etc.

你对谁都笑 2024-07-14 21:13:14

我也正在学习如何在工作中为小型应用程序编写流畅的界面。 我四处询问并进行了一些研究,发现编写流畅界面的一个好方法是使用“构建器模式”,阅读更多相关信息 此处

本质上,这就是我开始我的工作的方式:

public class Coffee
{
    private bool _cream;
    private int _ounces;

    public Coffee Make { get new Coffee(); }

    public Coffee WithCream()
    {
        _cream = true;
        return this;
    }

    public Coffee WithOuncesToServe(int ounces)
    {
        _ounces = ounces;
        return this;
    }
}

这是一个交叉帖子 我有一个类似的问题,用于在流畅的界面中实现闭包。

I too am just jumping on learning how to write a fluent interface for a small app at work. I've asked around and researched a little and found that a good approach for writing a fluent interface is using the "Builder pattern", read more about it here.

In essence, this is how I started mine:

public class Coffee
{
    private bool _cream;
    private int _ounces;

    public Coffee Make { get new Coffee(); }

    public Coffee WithCream()
    {
        _cream = true;
        return this;
    }

    public Coffee WithOuncesToServe(int ounces)
    {
        _ounces = ounces;
        return this;
    }
}

Here's a cross post to a similar question I have for implementing a closure in a fluent interface.

抽个烟儿 2024-07-14 21:13:14

一件事是,您必须考虑英语语法的形态,并确保您没有在下面引入未记录的顺序耦合。

// Snarky employees get a raise.
employees.WhereSnarky().GiveRaise();

// Depending on implementation, everyone may get a raise.
employees.GiveRaise().WhereSnarky();

One thing is that you have to account for the morphology of English syntax and ensure that you have not introduced undocumented sequential coupling underneath.

// Snarky employees get a raise.
employees.WhereSnarky().GiveRaise();

vs.

// Depending on implementation, everyone may get a raise.
employees.GiveRaise().WhereSnarky();
人疚 2024-07-14 21:13:14

不久前我也有过和你现在一样的疑问。 我已经做了一些研究,现在我正在写一些帖子来帮助解决这些主题。

在我的博客上查看:

指南C# 中的流畅界面设计第 1 部分

在接下来的文章中,我将涵盖您提到的每一点。

此致
安德烈·维亚纳

Sometime ago I had the same doubts you are having now. I've done some research and now I'm writing some posts to help in those topics.

Check it at my blog:

Guidelines to Fluent Interface design in C# part 1

And in the following posts I will cover every one of the points you mentioned.

Best regards
André Vianna

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