C#:返回“this” 用于方法嵌套?
我有一个类,我必须多次调用一两个方法。 这些方法当前返回 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); }
}
第一个可以这样使用:
var a = new Adder();
a.Add(4);
a.Remove(1);
a.Add(7);
a.Remove(3);
其他两个可以这样使用:
var a = new Adder()
.Add(4)
.Remove(1)
.Add(7)
.Remove(3);
唯一的区别是第一种情况中的 a
是new Adder()
而后者是最后一个方法的结果。
我发现第一个很快就变得……一遍又一遍地写很烦人。 所以我想使用其他版本之一。
第三种方法的工作原理与许多其他方法类似,例如许多 String 方法和 IEnumerable 扩展方法。 我想这有它积极的一面,因为你可以做类似 var a = new Adder(); 的事情。 var b = a.Add(5);
然后有一个是 0,一个是 5。但与此同时,一直创建新对象不是有点昂贵吗? 第一个对象什么时候会死亡? 第一个方法什么时候返回? 或者?
无论如何,我喜欢返回 this
的那个,并且认为我会使用它,但我很好奇知道其他人对这个案例的看法。 以及什么是最佳实践。
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:
// 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.
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?
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
“返回此”样式有时称为流畅界面,是一种常见做法。
The 'return this' style is sometimes called a fluent interface and is a common practice.
我喜欢“流畅的语法”并且会选择第二个。 毕竟,对于那些对流畅语法感到不舒服的人来说,您仍然可以将它作为第一个使用。
使像加法器这样的界面更易于使用的另一个想法是:
我总是尝试制作简短且易于阅读的界面,但许多人喜欢编写尽可能复杂的代码。
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:
I always try to make short and easy-to-read interfaces, but many people like to write the code as complicated as possible.
链接是一件好事,并且是某些框架的核心(例如 Linq 扩展和 jQuery 都大量使用它)。
无论您创建一个新对象还是
返回 this
取决于您期望初始对象的行为方式:jQuery 中的链接将更改您的原始对象 - 它已返回 this。
这是预期的行为 - do do else 基本上会克隆 UI 元素。
Linq 中的链接将使您的原始集合保持不变。 这也是预期的行为 - 每个链式函数都是一个过滤器或转换,并且原始集合通常是不可变的。
哪种模式更适合您正在做的事情?
Chaining is a nice thing to have and is core in some frameworks (for instance Linq extensions and jQuery both use it heavily).
Whether you create a new object or
return this
depends on how you expect your initial object to behave: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.
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.
Which pattern better suits what you're doing?
我认为对于简单的接口,“流畅”的接口非常有用,特别是因为它实现起来非常简单。 流畅界面的价值在于它消除了许多妨碍理解的无关内容。 开发这样的界面可能会花费很多时间,尤其是当界面开始涉及的时候。 你应该担心接口的使用如何“读取”; 在我看来,这种界面最引人注目的用途是它如何传达程序员的意图,而不是它节省的字符数量。
为了回答你的具体问题,我喜欢“返回这个”风格。 我对流畅界面的典型用途是定义一组选项。 也就是说,我创建该类的一个实例,然后在该实例上使用流畅的方法来定义该对象所需的行为。 如果我有是/否选项(例如日志记录),我尝试不使用“setLogging(bool state)”方法,而是使用两种方法“WithLogging”和“WithoutLogging”。 这需要更多的工作,但最终结果的清晰度非常有用。
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.
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.
考虑一下:如果您 5 年后再次查看这段代码,这对您来说有意义吗? 如果是这样,那么我想你可以继续。
不过,对于这个特定的示例,重载
+
和-
运算符似乎会使事情变得更清晰并完成相同的事情。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.
For this specific example, though, it would seem that overloading the
+
and-
operators would make things clearer and accomplish the same thing.对于您的具体情况,重载算术运算符可能是最好的解决方案。
对于
返回
this
(Fluent 接口)是创建表达式的常见做法 - 单元测试和模拟框架经常使用它。 Fluent Hibernate 是另一个示例。返回一个新实例可能也是一个不错的选择。 它允许你使你的类不可变——一般来说这是一件好事,并且在多线程的情况下非常方便。 但是,如果不变性对您没有用,请考虑一下对象创建开销。
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.
如果你称它为 Adder,我会返回它。 然而,Adder 类包含答案有点奇怪。
您可以考虑使其类似于 MyNumber 并创建一个 Add() 方法。
理想情况下(恕我直言),这不会更改存储在实例中的数字,而是使用您返回的新值创建一个新实例:
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.
You might consider making it something like MyNumber and create an Add()-method.
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:
第二个和第三个解决方案之间的主要区别在于,通过返回一个新实例而不是这个实例,您可以“捕获”处于某种状态的对象并从该状态继续。
在这种情况下,b 和 c 都以 a 中捕获的状态作为起点。
我在阅读 Growing Object-Oriented Software 中构建测试域对象的模式时遇到了这个习惯用法,由 Steve Freeman 的测试指导; 纳特·普莱斯。
关于您关于实例生命周期的问题:我认为一旦删除或添加的调用返回,它们就有资格进行垃圾收集。
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.
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.
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.