如何将方法作为参数传递?

时间:2010-12-10 08:03:06

标签: c# asp.net c#-4.0

我刚刚注意到我在ASP.NET应用程序中重复了很多C#代码,因此想要创建一个通用方法。我有一系列这样的私有方法:

private void PopulateMyRepeatedControl()
{
    DBUtil DB = new DBUtil();
    DataTable symbols = GetSelectedSymbols();
    DataTable tradeGrades = GetSelectedTradeGrades();
    DataTable executionGrades = GetSelectedExecutionGrades();        

    chtMyRepeatedChart.DataSource = DB.MyRepeatedCall (
        int.Parse(txtStartBalance.Text),
        int.Parse(ddlTradeTypes.SelectedValue),
        ddlRepeatedTrades.SelectedValue,
        radSide.SelectedValue,
        ddlTradeSetups.SelectedValue,
        symbols,
        ddlChartTimeFrames.SelectedValue,
        int.Parse(ddlHours.SelectedValue),
        int.Parse(ddlYears.SelectedValue),
        int.Parse(ddlMonths.SelectedValue),
        int.Parse(ddlDays.SelectedValue),
        int.Parse(ddlNumSCs.SelectedValue),
        txtDateFrom.Text,
        txtDateTo.Text,
        tradeGrades,
        executionGrades,
        int.Parse(txtMinProfitPips.Text),
        int.Parse(txtMaxProfitPips.Text));

    chtMyRepeatedChart.DataBind();
}

所以,我想替换DB.MyRepeatedCallchtMyRepeatedChart并将它们作为参数传递给泛型函数。那可能吗?我的表单上有很多图表,它们使用相同数量的参数。

由于

更新 根据弗雷德里克的解决方案,我做到了这一点:

private delegate IEnumerable<DataTable> GetDataSource(
    int TradeType,
    string RepeatedTrades,
    string Side,
    string TradeSetup,
    DataTable symbols,
    string ChartTimeFrame,
    int Hour,
    int Year,
    int Month,
    int Day,
    int NumSCs,
    string DateFrom,
    string DateTo,
    DataTable TradeGrades,
    DataTable ExecutionGrades,
    int MinProfitPips,
    int MaxProfitPips);

private void PopulateControl(Chart chart, GetDataSource getDataSource)
{
    //DBUtil DB = new DBUtil();
    DataTable symbols = GetSelectedItems("symbol", listSymbols);
    DataTable tradeGrades = GetSelectedItems("tradeGrade", listTradeGrades);
    DataTable executionGrades = GetSelectedItems("executionGrade", listExecutionGrades);

    chart.DataSource = getDataSource(
        int.Parse(ddlTradeTypes.SelectedValue),
        ddlRepeatedTrades.SelectedValue,
        radSide.SelectedValue,
        ddlTradeSetups.SelectedValue,
        symbols,
        ddlChartTimeFrames.SelectedValue,
        int.Parse(ddlHours.SelectedValue),
        int.Parse(ddlYears.SelectedValue),
        int.Parse(ddlMonths.SelectedValue),
        int.Parse(ddlDays.SelectedValue),
        int.Parse(ddlNumSCs.SelectedValue),
        txtDateFrom.Text,
        txtDateTo.Text,
        tradeGrades,
        executionGrades,
        int.Parse(txtMinProfitPips.Text),
        int.Parse(txtMaxProfitPips.Text));

    chart.DataBind();        
}       

我用这个命令调用函数:

PopulateControl (chtEquityCurve, DB.GetAccountBalances());

我在intellisense中收到此错误: No overload for method 'GetAccountBalances' takes 0 arguments.

4 个答案:

答案 0 :(得分:6)

首先,创建一个委托类型(通常我建议人们使用一个可用的Func代表,但它们最多只支持16个输入参数,你有18个)。给它一个合适的名称并定义所有输入参数,使它们具有正确的类型和描述性名称。让代理人返回IEnumerable<T>

public delegate IEnumerable<WhateverTypeIsReturned> GetDataSource(int firstParam, [...]);

然后,修改PopulateMyRepeatedControl,使其如下所示:

private void PopulateMyRepeatedControl(Chart chart, GetDataSource getDataSource)
{
    DBUtil DB = new DBUtil();
    DataTable symbols = GetSelectedSymbols();
    DataTable tradeGrades = GetSelectedTradeGrades();
    DataTable executionGrades = GetSelectedExecutionGrades();        

    chart.DataSource = getDataSource (
        int.Parse(txtStartBalance.Text),
        int.Parse(ddlTradeTypes.SelectedValue),
        ddlRepeatedTrades.SelectedValue,
        radSide.SelectedValue,
        ddlTradeSetups.SelectedValue,
        symbols,
        ddlChartTimeFrames.SelectedValue,
        int.Parse(ddlHours.SelectedValue),
        int.Parse(ddlYears.SelectedValue),
        int.Parse(ddlMonths.SelectedValue),
        int.Parse(ddlDays.SelectedValue),
        int.Parse(ddlNumSCs.SelectedValue),
        txtDateFrom.Text,
        txtDateTo.Text,
        tradeGrades,
        executionGrades,
        int.Parse(txtMinProfitPips.Text),
        int.Parse(txtMaxProfitPips.Text));

    chart.DataBind();
}

调用方法时,只需传递图表和用于收集数据的方法:

PopulateMyRepeatedControl(oneChart, OneDataCollectionMethod);
PopulateMyRepeatedControl(anotherChart, AnotherDataCollectionMethod);

当然,TheDataCollectionMethod必须具有正确的签名,否则代码将无法编译。

<强>更新
关于你的更新;请注意,您希望将该方法作为参数传递,而不是调用它:

PopulateControl (chtEquityCurve, DB.GetAccountBalances);

请注意,方法名称后面没有paranthesis。

答案 1 :(得分:1)

我认为您应该考虑使用一些OOP概念而不是参数化方法名称。因为你有一个方法,它接受实际上是控件的参数,想想把它分成不同的类。

首先,您应该考虑重新分解代码,因为单个方法的参数太多。您可以将所有参数封装到类

public class RepeatedCallParameters
{
   public string StartBalance{get;set;}

   ...

   ...
}

然后你可以有一个包含所有这些参数的抽象类和一个方法PrepareRepeatedCallParameters()

public abstract class ChartProperties : Page
{
    protected abstract int StartBalance {get;}

    public RepeatedCallParameters PrepareRepeatedCallParameters()
    {
         RepeatedCallParameters p = new RepeatedCallParamters();
         p.StartBalance = StartBalance;
         return p;  
    }
}

然后

您可以在页面

中实现此类
public class YourPage: ChartProperties
{
   protected override int StartBalance
   {
     get {return int.Parse(txtStartBalance.Text);} 
   }

   //All properties
   ..

   private void BindChartData()
   {
      RepeatedCallParameter p  = PrepareRepeatedCallParameters();
      Chart.DataSource = DB.RepeatedCall(p);
      Chart.DataBind();   
   }
}

通过这种方式,您可以在单个位置(即抽象类)中填充参数的代码。

答案 2 :(得分:1)

如下所示

PopulateMyRepeatedControl(Chart c , Func<List<List<T>>>  actionToBeCalled)  

答案 3 :(得分:0)

考虑使用委托,可以将其视为类型安全的函数指针。委托由委托类型和委托实例组成。我建议使用内置的泛型委托类型Action和Func。动作没有返回类型,Func没有。

public void MyMethod(Func<int, bool> predicate)
{
  if (predicate(5))
  {
    // true
  }
  else
  {
    // false
  }
}

// To call MyMethod, pass a delegate instance (here we are using a lambda expression)
MyMethod(x => x > 5);

委托实例从MyMethod调用(作为谓词参数),并且由于使用了逻辑,如果值为5,则返回false,否则返回任何大于5的值,true。您可以看到谓词的逻辑如何与MyMethod方法分离,这使得MyMethod可以重用于任何逻辑。

注意Func中使用的最后一个泛型类型是返回类型,Action没有返回类型。两个委托类型最多需要16个参数,但如果您需要这么多,可能需要考虑一下您的设计!