C#:为方法嵌套返回“this”?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/781648/
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
C#: Returning 'this' for method nesting?
提问by Svish
I have a class that I have to call one or two methods a lot of times after each other. The methods currently return void
. I was thinking, would it be better to have it return this
, so that the methods could be nested? or is that considerd very very very bad? or if bad, would it be better if it returned a new object of the same type? Or what do you think? As an example I have created three versions of an adder class:
我有一个类,我必须多次调用一两个方法。这些方法当前返回void
. 我在想,让它返回会更好this
,以便方法可以嵌套吗?或者这被认为非常非常非常糟糕?或者如果不好,如果它返回一个相同类型的新对象会更好吗?或者你怎么看?例如,我创建了一个加法器类的三个版本:
// Regular
class Adder
{
public Adder() { Number = 0; }
public int Number { get; private set; }
public void Add(int i) { Number += i; }
public void Remove(int i) { Number -= i; }
}
// Returning this
class Adder
{
public Adder() { Number = 0; }
public int Number { get; private set; }
public Adder Add(int i) { Number += i; return this; }
public Adder Remove(int i) { Number -= i; return this; }
}
// Returning new
class Adder
{
public Adder() : this(0) { }
private Adder(int i) { Number = i; }
public int Number { get; private set; }
public Adder Add(int i) { return new Adder(Number + i); }
public Adder Remove(int i) { return new Adder(Number - i); }
}
The first one can be used this way:
第一个可以这样使用:
var a = new Adder();
a.Add(4);
a.Remove(1);
a.Add(7);
a.Remove(3);
The other two can be used this way:
另外两个可以这样使用:
var a = new Adder()
.Add(4)
.Remove(1)
.Add(7)
.Remove(3);
Where the only difference is that a
in the first case is the new Adder()
while in the latter it is the result of the last method.
唯一的区别是a
在第一种情况下是new Adder()
while 在后一种情况下它是最后一种方法的结果。
The first I find that quickly become... annoying to write over and over again. So I would like to use one of the other versions.
我发现第一个很快就会变得……一遍又一遍地写很烦人。所以我想使用其他版本之一。
The third works kind of like many other methods, like many String methods and IEnumerable extension methods. I guess that has its positive side in that you can do things like var a = new Adder(); var b = a.Add(5);
and then have one that was 0 and one that was 5. But at the same time, isn't it a bit expensive to create new objects all the time? And when will the first object die? When the first method returns kind of? Or?
第三种工作方式类似于许多其他方法,例如许多 String 方法和 IEnumerable 扩展方法。我想这有其积极的一面,你可以做这样的事情var a = new Adder(); var b = a.Add(5);
,然后有一个是 0 一个是 5。但与此同时,一直创建新对象是不是有点贵?第一个物体什么时候死?当第一个方法返回什么样的?或者?
Anyways, I like the one that returns this
and think I will use that, but I am very curious to know what others think about this case. And what is considered best practice.
无论如何,我喜欢返回this
并认为我会使用它的那个,但我很想知道其他人对此案的看法。以及什么被认为是最佳实践。
采纳答案by Brian
The 'return this' style is sometimes called a fluent interfaceand is a common practice.
'return this' 风格有时被称为流畅的界面,是一种常见的做法。
回答by Adam Robinson
Consider this: if you come back to this code in 5 years, is this going to make sense to you? If so, then I suppose you can go ahead.
想一想:如果你在 5 年后回到这个代码,这对你有意义吗?如果是这样,那么我想你可以继续。
For this specific example, though, it would seem that overloading the +
and -
operators would make things clearer and accomplish the same thing.
但是,对于这个特定示例,重载+
and-
运算符似乎会使事情更清楚并完成相同的事情。
回答by Stefan Steinegger
I like "fluent syntax" and would take the second one. After all, you could still use it as the first, for people who feel uncomfortable with fluent syntax.
我喜欢“流畅的语法”,并会选择第二个。毕竟,对于那些对流畅的语法感到不舒服的人,您仍然可以将它用作第一个。
another idea to make an interface like the adders one easier to use:
使像加法器这样的界面更易于使用的另一个想法:
public Adder Add(params int[] i) { /* ... */ }
public Adder Remove(params int[] i) { /* ... */ }
Adder adder = new Adder()
.Add(1, 2, 3)
.Remove(3, 4);
I always try to make short and easy-to-read interfaces, but many people like to write the code as complicated as possible.
我总是尝试制作简短易读的界面,但很多人喜欢编写尽可能复杂的代码。
回答by Daniel Brückner
For your specific case, overloading the arithmetic operators would be probably the best solution.
Returning
this
(Fluent interface) is common practice to create expressions - unit testing and mocking frameworks use this a lot. Fluent Hibernate is another example.Returning a new instance might be a good choice, too. It allows you to make your class immutable - in general a good thing and very handy in the case of multithreading. But think about the object creation overhead if immutability is of no use for you.
对于您的具体情况,重载算术运算符可能是最好的解决方案。
返回
this
(Fluent 接口)是创建表达式的常见做法 - 单元测试和模拟框架经常使用它。Fluent Hibernate 是另一个例子。返回一个新实例也可能是一个不错的选择。它允许您使您的类不可变 - 通常是一件好事,并且在多线程的情况下非常方便。但是,如果不变性对您没有用处,请考虑创建对象的开销。
回答by Lennaert
If you call it Adder, I'd go with returning this. However, it's kind of strange for an Adder class to contain an answer.
如果你称它为加法器,我会返回这个。但是,Adder 类包含答案有点奇怪。
You might consider making it something like MyNumber and create an Add()-method.
您可能会考虑将其设置为 MyNumber 之类的内容并创建一个 Add() 方法。
Ideally (IMHO), that would not change the number that is stored inside your instance, but create a new instance with the new value, which you return:
理想情况下(恕我直言),这不会更改存储在您的实例中的数字,而是使用您返回的新值创建一个新实例:
class MyNumber
{
...
MyNumber Add( int i )
{
return new MyNumber( this.Value + i );
}
}
回答by JonStonecash
I think that for simple interfaces, the "fluent" interface is very useful, particularly because it is very simple to implement. The value of the fluent interface is that it eliminates a lot of the extraneous fluff that gets in the way of understanding. Developing such an interface can take a lot of time, especially when the interface starts to be involved. You should worry about how the usage of the interface "reads"; In my mind, the most compelling use for such an interface is how it communicates the intent of the programmer, not the amount of characters that it saves.
我认为对于简单的接口,“fluent”接口非常有用,特别是因为它实现起来非常简单。流畅界面的价值在于它消除了许多妨碍理解的无关紧要的东西。开发这样的界面可能需要很多时间,尤其是在开始涉及界面时。你应该担心接口的用法是如何“读取”的;在我看来,这种界面最引人注目的用途是它如何传达程序员的意图,而不是它保存的字符数量。
To answer your specific question, I like the "return this" style. My typical use of the fluent interface is to define a set of options. That is, I create an instance of the class and then use the fluent methods on the instance to define the desired behavior of the object. If I have a yes/no option (say for logging), I try not to have a "setLogging(bool state)" method but rather two methods "WithLogging" and "WithoutLogging". This is somewhat more work but the clarity of the final result is very useful.
要回答您的具体问题,我喜欢“返回此”样式。我对 fluent 界面的典型用途是定义一组选项。也就是说,我创建了一个类的实例,然后在实例上使用 fluent 方法来定义对象的所需行为。如果我有一个是/否选项(比如日志记录),我会尽量不使用“setLogging(bool state)”方法,而是使用“WithLogging”和“WithoutLogging”两种方法。这需要更多的工作,但最终结果的清晰度非常有用。
回答by Keith
Chaining is a nice thing to have and is core in some frameworks (for instance Linq extensions and jQuery both use it heavily).
链接是一件好事,并且是某些框架的核心(例如 Linq 扩展和 jQuery 都大量使用它)。
Whether you create a new object or return this
depends on how you expect your initial object to behave:
是创建新对象还是return this
取决于您期望初始对象的行为方式:
var a = new Adder();
var b = a.Add(4)
.Remove(1)
.Add(7)
.Remove(3);
//now - should a==b ?
Chaining in jQuery will have changed your original object - it has returned this. That's expected behaviour - do do otherwise would basically clone UI elements.
在 jQuery 中链接会改变你的原始对象——它已经返回了这个。这是预期的行为 - 否则基本上会克隆 UI 元素。
Chaining in Linq will have left your original collection unchanged. That too is expected behaviour - each chained function is a filter or transformation, and the original collection is often immutable.
在 Linq 中链接将使您的原始收藏保持不变。这也是预期的行为 - 每个链式函数都是一个过滤器或转换,并且原始集合通常是不可变的。
Which pattern better suits what you're doing?
哪种模式更适合您的工作?
回答by Keith
The main difference between the second and third solution is that by returning a new instance instead of this you are able to "catch" the object in a certain state and continue from that.
第二个和第三个解决方案之间的主要区别在于,通过返回一个新实例而不是这个,您可以“捕获”处于某种状态的对象并从该状态继续。
var a = new Adder() .Add(4);
var b = a.Remove(1);
var c = a.Add(7) .Remove(3);
var a = new Adder() .Add(4);
var b = a.Remove(1);
var c = a.Add(7) .Remove(3);
In this case both b and c have the state captured in a as a starting point. I came across this idiom while reading about a pattern for building test domain objects in Growing Object-Oriented Software, Guided by Tests by Steve Freeman; Nat Pryce.
在这种情况下, b 和 c 都将 a 中捕获的状态作为起点。我在阅读Steve Freeman 的测试指导下的 Growing Object-Oriented Software 中构建测试域对象的模式时遇到了这个习语;纳特·普莱斯。
On your question regarding the lifetime of your instances: I would exspect them to be elligible for garbage collection as soon as the invocation of Remove or Add are returning.
关于您的实例生命周期的问题:我希望它们在调用 Remove 或 Add 后立即有资格进行垃圾收集。