在 C# 3 中编写流畅接口的技巧
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/224730/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Tips for writing fluent interfaces in C# 3
提问by Scott McKenzie
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:
我在寻找一些关于 C# 中流畅界面的好技巧。我只是自己了解它,但很想听听其他人在我阅读的文章之外的想法。特别是我在追求:
- when is fluent too much?
- are there any fluent patterns?
- what is in C# that makes fluent interfaces more fluent (e.g. extension methods)
- is a complex fluent interface still a fluent one?
- refactoring to arrive at a fluent interface or refactoring an existing fluent interface
- any good examples out there that you have worked with or could recommend?
- 什么时候流利太多了?
- 有流畅的模式吗?
- C# 中什么使流畅的接口更加流畅(例如扩展方法)
- 一个复杂的流畅界面仍然是一个流畅的界面吗?
- 重构以达到流畅的界面或重构现有的流畅界面
- 您曾经使用过或可以推荐的任何好例子吗?
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.
先感谢您。
采纳答案by Mendelt
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.
Fluent 接口的构造使得它们像编程语言一样编写,只允许用自然语言表达的一小部分内容,但它们读起来像自然语言。
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.
所以稍微限定一下我的观点。编写复杂但易于阅读的流畅界面仍然可以流畅。
回答by Mendelt
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 语句 (C# 2.0) 在特定上下文中运行代码,例如:
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.
这使用 Transaction 的构造函数和处置器来设置事务,然后在此上下文中运行代码。
The second does almost the same but with lambda's, this is used a lot in Rhino Mocks for example.
第二个几乎相同,但对于 lambda,这在 Rhino Mocks 中经常使用。
(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:
最著名的流畅接口是使用返回类型来链接方法调用。大多数方法都会返回 this,因此您可以在同一对象上链接调用。但是您也可以根据调用的方法返回不同的对象来更改上下文。如果您有一个只能在事务中运行的对象(对不起,想不出不同的例子),您可以给它一个 StartTransaction 方法,该方法返回一个初始化的事务,您可以在其中运行 call run 和 stoptransaction,在伪代码中:
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.
当然你需要添加各种错误处理等。
回答by sbohlen
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!
...比实际编写代码更容易阅读!
回答by sbohlen
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/
在使用继承和流畅的接口时,您会遇到困难,因为使用多态方法会破坏您的调用链,而且您绝对不希望通过在不需要的地方使用丑陋的强制转换和括号使接口变得不流畅。我写了一篇关于一种模式的文章,该模式为您提供了使用通用构建器和具有通用约束的通用扩展方法的解决方法:http: //liviutrifoi.wordpress.com/2009/02/16/fluent-interfaces-constraints-at-编译时/
回答by Finglas
Moq hides unreleated methods such as equals, ToString
and so on to make their fluent interface even easier to use.
Moq 隐藏了不相关的方法,例如 equals 等,ToString
以使其流畅的界面更易于使用。
Hiding System Objectis an article explaining the benefit of doing this.
隐藏系统对象是一篇解释这样做的好处的文章。
回答by sam
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 questionI have for implementing a closure in a fluent interface.
这是我在流畅界面中实现闭包的类似问题的交叉帖子。
回答by Andre Vianna
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
最好的问候安德烈·维安娜
回答by An00bus
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();