将函数作为参数传递给另一个函数

时间:2018-10-31 15:28:58

标签: c# c#-4.0

在我的应用程序中,我有一些函数可以循环访问表单中的所有组件,以建立一些类似于以下属性的属性:

用于仅在查看数据时将表单中的所有文本框设置为只读的函数:

public void SetReadOnly(Control.ControlCollection controls, bool readOnly)
{
    foreach(var panel in controls.OfType<Panel>())
    {
        SetReadOnly(panel.Controls, readOnly);
    }

    foreach(var tabpageview in controls.OfType<TabPageView>())
    {
        foreach(var tabpageviewpage in tabpage.Controls)
        {
            SetReadOnly(tagpageviewpage.Controls, readOnly);
        }
    }

    foreach(var textbox in controls.OfType<TextBox>())
    {
        textbox.ReadOnly = readOnly;
    }
}

用于将数据插入数据库后清除所有文本框内容的函数:

public void CleanTextBox(Control.ControlCollection controls)
{
    foreach(var panel in controls.OfType<Panel>())
    {
        CleanTextBox(panel.Controls);
    }

    foreach(var tabpageview in controls.OfType<TabPageView>())
    {
        foreach(var tabpageviewpage in tabpage.Controls)
        {
            CleanTextBox(tagpageviewpage.Controls);
        }
    }

    foreach(var textbox in controls.OfType<TextBox>())
    {
        textbox.Text = "";
    }
}

该函数将接收字段列表,并将带有该名称的标签涂成红色以标记必填项:

public void SetRequired(Control.ControlCollection controls, List<string> requiredFields)
{
    foreach(var panel in controls.OfType<Panel>())
    {
        SetRequired(panel.Controls, requiredFields);
    }

    foreach(var tabpageview in controls.OfType<TabPageView>())
    {
        foreach(var tabpageviewpage in tabpage.Controls)
        {
            SetRequired(tagpageviewpage.Controls, requiredFields);
        }
    }

    foreach(var field in requiredFields)
    {
        FindLabelByName(field).Foreground(Color.Red);
    }
}    

如您所见,所有这些函数都有一些共同点,它们会收到一组控件并在它们上循环。如果它是面板,tabpageview或具有子元素的其他组件,则它将再次循环直到找到其文本框并执行一些操作。

是否可以使一个函数接收另一个函数作为参数,所以如果我开始使用组框,可以将其放在一个函数中,而不必将其放在所有函数中?像这样的东西。

public void LoopComponents(Control.ControlCollection controls, xxx function)
{
    foreach(var panel in controls.OfType<Panel>())
    {
        LoopComponents(panel.controls, function);
    }

    foreach(var tabpageview in controls.OfType<TabPageView>())
    {
        foreach(var tabpageviewpage in tabpageview.Controls)
        {
            LoopComponents(tabpageviewpage.Controls, function);
        }
    }

    function();
}

public void SetReadOnly(Control.ControlCollection controls, bool readOnly)
{
    foreach(var textbox in controls.OfType<TextBox>())
    {
        textbox.ReadOnly = readOnly;
    }
}

public void CleanTextBox(Control.ControlCollection controls)
{
    foreach(var textbox in controls.OfType<TextBox>())
    {
        textbox.Text = "";
    }
}

public void SetRequired(Control.ControlCollection controls, List<string> requiredFields)
{
    foreach(var field in requiredFields)
    {
        FindLabelByName(field).Foreground(Color.Red);
    }
}   

public void Test()
{
    LoopComponents(Controls, SetReadOnly(Controls, true));
    LoopComponents(Controls, CleanTextBox(Controls));
    LoopComponents(Controls, SetRequired(Controls, requiredFieldsList));
}

当前我正在使用C#4.0,但是如果在更高版本中可以使用,则没关系,只是好奇地知道是否可能。谢谢

1 个答案:

答案 0 :(得分:0)

您必须定义一个委托或使用预定义的委托,例如Action <>和Func <>。 代表将定义方法签名:

 delegate void Operator(Control.ControlCollection controls);

,您可以通过以下方式修改LoadComponent:

 LoadComponent(Control.ControlCollection controls, Operator Op)
 {
     foreach(var control in controls.OfType<Panel>())
     {
        Op(panel.controls);
     }
     //....
 }

,您可以编写一些运算符,例如:

 public void CleanTextBox(Control.ControlCollection controls)
 {
     foreach(var textbox in controls.OfType<TextBox>())
     {
        textbox.Text = "";
     }
 }

注意:上述功能CleanTextBox中的输入和输出在操作员委托中相同。因此它将与操作员委托匹配。

使用预定义的委托人:

您可以使用预定义的委托。由于您的函数无效,因此可以使用Action的重载之一:

 LoadComponent(Action<Control.ControlCollection controls, Action<Control.ControlCollection> Op)
 {
     foreach(var control in controls.OfType<Panel>())
     {
        Op(panel.controls);
     }
     //....
 }

此新版本刚刚删除了代理减速度。 在两种工作方式中,您都可以使用以下代码对数据进行操作:

LoopComponents(Controls, CleanTextBox(Controls));

**当您希望有一个返回值时,Func委托很有用**

编辑:如果要使用一个委托调用不同的方法,则必须创建新方法来统一这些方法:

重写LoadComponents

  LoadComponents(Control.ControlCollection controls, Action Op)
  {
       Op.Invoke();
       //....
  }

(这是Lambda表达式,用于统一您的方法)

 LoadComponents(Controls, new Action(()=>{ SetRequired(Controls,true);}));
 LoopComponents(Controls, new Action(()=>{ CleanTextBox(Controls);})); 
 LoopComponents(Controls, new Action(()=>{ SetRequired(Controls, requiredFieldsList);});