65.9K
CodeProject 正在变化。 阅读更多。
Home

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

2010年12月20日

CPOL

1分钟阅读

viewsIcon

17431

使用匿名方法有助于限制仅在单个方法内部可调用的代码的可见性

为什么有人会限制程序集内部代码的可见性和作用域?原因与使用有限变量作用域的原因相同。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
© . All rights reserved.