当然,不是在可读性方面,因为您始终可以将单独的方法安排到单独的行中。相反,无论出于何种原因,将过多的方法链接在一起是危险的吗?我主要使用方法链来节省宣布单个一用变量的空间,传统上使用返回方法而不是修改调用者的方法。除了字符串方法,那些我有点无情地链。无论如何,我有时担心在一行中使用异常长的方法链的影响。
假设我需要根据某人的用户名更新一个项目的值。不幸的是,检索正确用户的最短方法如下所示。
SPWeb web = GetWorkflowWeb();
SPList list2 = web.Lists["Wars"];
SPListItem item2 = list2.GetItemById(3);
SPListItem item3 = item2.GetItemFromLookup("Armies", "Allied Army");
SPUser user2 = item2.GetSPUser("Commander");
SPUser user3 = user2.GetAssociate("Spouse");
string username2 = user3.Name;
item1["Contact"] = username2;
所有2或3的东西只能持续一次通话,所以我可能会将其压缩为以下(这也让我摆脱了一个多余的1):
SPWeb web = GetWorkflowWeb();
item["Contact"] = web.Lists["Armies"]
.GetItemById(3)
.GetItemFromLookup("Armies", "Allied Army")
.GetSPUser("Commander")
.GetAssociate("Spouse")
.Name;
不可否认,当它在一行中以及int.Parse(ddlArmy.SelectedValue.CutBefore(";#", false))
而不是3
时,它看起来要长得多。然而,这是这些链的平均长度之一,我可以很容易地预见到一些特别长的计数。排除可读性,对于这10个以上的方法链,我应该担心什么吗?或者使用非常长的方法链是否有害?
答案 0 :(得分:33)
方法链的持续时间没有技术限制。
但是,可能会出现问题的三个方面是调试,异常处理和资源处理。
调试很复杂,因为链接如此优雅 - 缺少中间临时变量。不幸的是,没有临时变量,在调试变得痛苦时检查中间结果。
由于您无法隔离从一种方法到另一种方法引发的异常,因此异常处理变得复杂。通常情况下,如果您无法对异常做出有意义的事情,这不是问题 - 只需让它在调用链中传播即可。但是,如果您稍后意识到需要进行异常处理,则必须重构链接语法才能插入适当的try / catch处理程序。
与异常处理类似,是确定性处置资源的情况。在C#中实现这一目标的最简单方法是使用using()
- 遗憾的是,链接语法排除了这一点。如果您正在调用返回一次性对象的方法,那么最好避免链接语法,这样您就可以成为一名优秀的“代码公民”并尽早处理这些资源。
方法链接语法通常用于fluent APIs,它允许代码的语法更接近地反映您想要的操作顺序。 LINQ是.NET中的一个例子,经常可以看到流畅/链接语法。
答案 1 :(得分:7)
可读性是最大的问题,但通常这根本不是问题。
您还可以将LINQ查询语法描述为(在其下面)完全这样的设置。它只是让它看起来更漂亮;-p
一个可能的问题是您需要介绍using
或lock
等内容的地方。使用流畅的API,您可能只想删除这些组件,但这可能会在抛出异常时导致奇怪。
另一种可能的想法是,您可能希望围绕某些调用进行更细粒度的异常处理;但你总是可以打破流程:
var foo = bar.MethodA().MethodB(...).MethodC();
try {
foo.MethodD();
} catch (SomeSpecificException) {
//something interesting
}
或者您甚至可以在扩展方法中 以保持流畅的外观:
bar.MethodA().MethodB(...).MethodC().MyExtensionMethodD();
其中MyExtensionMethodD
是您通过特殊处理添加的(例外,锁定,使用等)。
答案 2 :(得分:6)
这被某些人认为是代码嗅觉而不是其他人。任何时候你看到以下内容:
Foo.getBar().getBlah().getItem().getName();
你应该真的在想,“我真正想要的是什么?”相反,您的方法可能包含函数调用:
String getName(Int _id, String _item)
{
return myBar.getName( _id, _item );
}
然后在课程中向下委派。然后,如果稍后更新某个类中的某些内容发生更改,您将确切地看到它发生的位置并可以在一个位置更改它。
答案 3 :(得分:4)
你应该考虑的唯一一个问题(如果你忽略了可读性)是资源处理和GC ..你应该问的问题是。
但是真的..天气你每行调用一个方法,或者将它们全部串起来以使它的所有结果在IL中相同(或者几乎相同)。
约什
答案 4 :(得分:0)
除了其他答案之外,您还可能遇到一个技术限制:很长的方法链会导致提供智能感知的服务崩溃,随后它们的主机进程(Linqpad 6、Visual Studio 2019 和其他可能)崩溃。
当我将用于跟踪个人工作的脚本从基于集合的 API 转换为流畅的 API 调用链时,我发现了这一点。我发现我拥有的代码会使我放入的任何 IDE 崩溃。研究使我发现了这个长期存在的 github 问题:https://github.com/dotnet/roslyn/issues/9795
很容易将很长的链分解成单独的语句。