将临时方法隐藏在调用方法的内部






4.62/5 (8投票s)
使用匿名方法有助于限制仅在单个方法内部可调用的代码的可见性
为什么有人会限制程序集内部代码的可见性和作用域?原因与使用有限变量作用域的原因相同。Pascal 和 Delphi ( .NET 的主要前身) 的用户怀念其局部方法——仅限于其他方法的作用域。然而,这个特性实际上在 .NET 和 C# 中是可用的。让我们考虑以下代码
void AdjustMargins(FrameworkElement frameworkElement) {
Thickness margin = frameworkElement.Margin;
Control parent = frameworkElement.Parent as FrameworkElement;
if (parent == null) return;
if (parent.Margin.Left > 0) margin.Left = 0;
if (parent.Margin.Right > 0) margin.Right = 0;
if (parent.Margin.Top > 0) margin.Left = 0;
if (parent.Margin.Bottom > 0) margin.Bottom = 0;
//..
frameworkElement.Margin = margin;
} //AdjustMargins
void AdjustLayout() {
AdjustMargins(panelTop);
AdjustMargins(panelButtons);
AdjustMargins(panelProperties);
AdjustMargins(panelOutput);
//..
} //AdjustLayout
它具体做什么并不重要。这段代码有什么问题?创建 AdjustMargins
方法作为单独方法的主要原因是基本的代码重用,因为它在 AdjustLayout
方法体中被调用多次。与此同时,这个示例表明 AdjustMargins
是一个 *临时* 方法,仅从 AdjustLayout
调用。所以,这段代码很好,但如果可以将 AdjustMargins
的可调用代码完全放在作用域内,并使其完全在作用域外部不可见,则可以使其更易于管理。如果正在开发的 Window
类足够小,则无关紧要,但如果它已经充斥着其他方法(或者将来可能会充斥),会怎么样?在这种情况下,减少类级别可见的方法数量确实有助于保持该类的可管理性。局部方法会在这方面有所帮助,但 .NET 中没有这种方法——除了匿名方法。使用匿名方法,可以达到与局部方法相同的效果。我们需要使用以下模式void AdjustLayout() {
System.Action<FrameworkElement> adjustMargins =
(FrameworkElement frameworkElement) => {
Thickness margin = frameworkElement.Margin;
Control parent = frameworkElement.Parent as FrameworkElement;
if (parent == null) return;
if (parent.Margin.Left > 0) margin.Left = 0;
if (parent.Margin.Right > 0) margin.Right = 0;
if (parent.Margin.Top > 0) margin.Left = 0;
if (parent.Margin.Bottom > 0) margin.Bottom = 0;
//...
frameworkElement.Margin = margin;
}; //adjustMargins
adjustMargins(panelTop);
adjustMargins(panelButtons);
adjustMargins(panelProperties);
adjustMargins(panelOutput);
//...
} //AdjustLayout
如果某些代码应该局部化但由两个或多个调用方法共享怎么办?委托是第一类对象,因此可以作为参数传递。这是一个更复杂的例子void AdjustLayout() {
System.Action<FrameworkElement> adjustMargins =
(FrameworkElement frameworkElement) => {
Thickness margin = frameworkElement.Margin;
Control parent = frameworkElement.Parent as FrameworkElement;
if (parent == null) return;
if (parent.Margin.Left > 0) margin.Left = 0;
if (parent.Margin.Right > 0) margin.Right = 0;
if (parent.Margin.Top > 0) margin.Left = 0;
if (parent.Margin.Bottom > 0) margin.Bottom = 0;
//...
frameworkElement.Margin = margin;
}; //adjustMargins
System.Action<FrameworkElement,
System.Action<FrameworkElement>>
adjustCombined =
(FrameworkElement frameworkElement,
System.Action<FrameworkElement> adjustMarginsMethod) => {
if (adjustMarginsMethod != null)
adjustMarginsMethod(frameworkElement);
//other adjustments...
};
foreach (var element in new FrameworkElement[] {
panelTop,
panelButtons, panelProperties, })
adjustMargins(element);
adjustMargins(panelOutput);
adjustCombined(panelOutput, adjustMargins);
//...
} //AdjustLayout