C#方法链可以"太长"吗?

Gra*_*ote 22 c# method-chaining

当然,不是在可读性方面,因为您总是可以将单独的方法安排到单独的行中.相反,无论出于何种原因,将过多的方法链接在一起是危险的吗?我主要使用方法链来节省宣布单个一用变量的空间,传统上使用返回方法而不是修改调用者的方法.除了字符串方法,那些我有点无情地链.无论如何,我有时担心在一行中使用异常长的方法链的影响.

假设我需要根据某人的用户名更新一个项目的值.不幸的是,检索正确用户的最短方法看起来如下所示.

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;
Run Code Online (Sandbox Code Playgroud)

一个2或3的所有东西只持续一次通话,所以我可能会将其压缩为以下(这也让我摆脱了一个多余的1):

SPWeb web = GetWorkflowWeb();
item["Contact"] = web.Lists["Armies"]
                     .GetItemById(3)
                     .GetItemFromLookup("Armies", "Allied Army")
                     .GetSPUser("Commander")
                     .GetAssociate("Spouse")
                     .Name;
Run Code Online (Sandbox Code Playgroud)

不可否认,当它在一条线上并且当你有int.Parse(ddlArmy.SelectedValue.CutBefore(";#", false))而不是时,它看起来要长得多3.然而,这是这些链的平均长度之一,我可以很容易地预见到一些特别长的计数.排除可读性,对于这10个以上的方法链,我应该担心什么吗?或者使用非常长的方法链是否有害?

LBu*_*kin 34

方法链的长度没有技术限制.

但是,可能存在问题的三个方面是调试,异常处理资源处理.

调试很复杂,因为链接如此优雅 - 缺少中间临时变量.不幸的是,没有临时变量,在调试变得痛苦时检查中间结果.

由于您无法隔离从一种方法到另一种方法引发的异常,因此异常处理变得复杂.通常情况下,如果您无法对异常做出有意义的事情,这不是问题 - 只需让它在调用链中传播即可.但是,如果你不知道在你需要异常处理稍后,你必须要重构链接语法能够插入适当的try/catch处理.

与异常处理类似的是确定性处置资源的情况.在C#中实现这一目标的最简单方法是using()- 不幸的是,链接语法排除了这一点.如果您正在调用返回一次性对象的方法,那么避免链接语法可能是一个好主意,这样您就可以成为一名优秀的"代码公民"并尽早处理这些资源.

方法链接语法通常用于流畅的API,它允许代码的语法更接近地反映您想要的操作顺序.LINQ是.NET中的一个例子,经常可以看到流畅/链接语法.


Mar*_*ell 7

可读性是最大的问题,但通常这根本不是问题.

您还可以将LINQ查询语法描述为(在其下面)完全是这样的设置.它只是让它看起来更漂亮;-p

一个可能的问题是你需要介绍像using或的东西lock; 使用流畅的API,您可能会想要简单地删除这些组件,但这可能会在抛出异常时导致奇怪.

另一种可能的想法是,您可能希望围绕某些调用进行更细粒度的异常处理; 但你总是可以打破流程:

var foo = bar.MethodA().MethodB(...).MethodC();
try {
    foo.MethodD();
} catch (SomeSpecificException) {
    //something interesting
}
Run Code Online (Sandbox Code Playgroud)

或者你甚至可以做的是在一个扩展方法,以保持流畅的外观:

bar.MethodA().MethodB(...).MethodC().MyExtensionMethodD();
Run Code Online (Sandbox Code Playgroud)

这里MyExtensionMethodD是你的特殊处理(例外,锁,使用等)添加一个.


whe*_*ies 6

这被某些人认为是代码嗅觉而不是其他人.任何时候您看到以下内容:

Foo.getBar().getBlah().getItem().getName();
Run Code Online (Sandbox Code Playgroud)

你应该真的在想,"我真正想要的是什么?" 相反,您的方法可能包含函数调用:

String getName(Int _id, String _item)
{
    return myBar.getName( _id, _item );
}
Run Code Online (Sandbox Code Playgroud)

然后在课堂上向下委派.然后,如果稍后更新某个类中的某些内容发生更改,您将确切地看到它发生的位置并可以在一个位置更改它.