Click here to Skip to main content
15,867,568 members
Articles / Programming Languages / C#
Tip/Trick

Hide Ad-hoc Methods Inside the Calling Method’s Body

Rate me:
Please Sign up or sign in to vote.
4.62/5 (8 votes)
21 Dec 2010CPOL1 min read 16.6K   3   2
Using anonymous methods helps to limit visibility of code callable just from within one method
Why would anyone restrict any code visibility and scope inside an assembly? Well, by the same reasons limited variable scope is used. The users of Pascal and Delphi (major predecessor of .NET) miss its local methods -- local to the scope of some other method. However, this feature is actually available with .NET and C#.

Let's consider the following code:

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


It does not really matter what it does. What's wrong in this code?

The major reason method AdjustMargins code is created as a separate method is elementary code reuse because it is called from the body of the method AdjustLayout more than once. At the same time, this sample suggests that AdjustMargins is an ad-hoc method called only from AdjustLayout. So, this code is just fine, but it could be a bit more manageable if the callable code of AdjustMargins could be placed entirely into the scope and made completely invisible outside of this scope.

If the Window class being developed is small enough, it does not matter, but what if it is already overwhelmed with other methods (or tends to be overwhelmed later down the road)? In this case, reducing number of methods visible at the level of the class really helps to keep this class manageable.

This is where local methods would help a bit, but there is no such thing in .NET -- with the exclusion of anonymous method. With the anonymous methods, one could achieve the same effect as with local methods. We need to use the following pattern:

C#
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


What if some code should be local but shared by two or more calling methods? Well, delegates are first-class objects, so they can be passed as parameters. Here is a more complex example:

C#
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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
United States United States
Physics, physical and quantum optics, mathematics, computer science, control systems for manufacturing, diagnostics, testing, and research, theory of music, musical instruments… Contact me: https://www.SAKryukov.org

Comments and Discussions

 
QuestionIs it really worth that? Pin
SergeyT228-Dec-10 12:11
SergeyT228-Dec-10 12:11 
The original code is more readable. I think it's more important.

On the other hand, you never know whether a function would be used somewhere else or not. Often it will. So it is more practical to create a separate function.
AnswerRe: Is it really worth that? Pin
Sergey Alexandrovich Kryukov28-Dec-10 17:38
mvaSergey Alexandrovich Kryukov28-Dec-10 17:38 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.