Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass in a method as a parameter?

Tags:

c#

asp.net

c#-4.0

I've just noticed I'm repeating a lot of C# code in my ASP.NET application so want to create a generic method. I have a series of private methods like this:

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();
}

So, I want to replace DB.MyRepeatedCall, chtMyRepeatedChart and pass them in as parameters to a generic function. Is that possible? I have many charts on my form that take the same number of parameters.

Thanks

UPDATE Following Frederik's solution I have done this:

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();        
}       

I am calling the function with this command:

PopulateControl (chtEquityCurve, DB.GetAccountBalances());

I get this error in the intellisense: No overload for method 'GetAccountBalances' takes 0 arguments.

like image 621
Mark Allison Avatar asked Feb 26 '23 15:02

Mark Allison


2 Answers

First, make a delegate type (typically I recomment people to use one of the available Func delegates, but they support only up to 16 input paramters, you have 18). Give it an appropriate name and define all the input parameters so they have the correct type and descriptive names. Make the delegate return an IEnumerable<T>:

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

Then, modify PopulateMyRepeatedControl so that it looks like this:

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();
}

When you call the method, simply pass the chart and the method to use for collecting data:

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

Of course, TheDataCollectionMethod must have the correct signature, otherwise the code will not compile.

Update
Regarding your update; note that you want to pass the method as an argument, not invoke it:

PopulateControl (chtEquityCurve, DB.GetAccountBalances);

Note that there are no paranthesis after the method name.

like image 69
Fredrik Mörk Avatar answered Mar 11 '23 00:03

Fredrik Mörk


something like below

PopulateMyRepeatedControl(Chart c , Func<List<List<T>>>  actionToBeCalled)  
like image 20
TalentTuner Avatar answered Mar 10 '23 23:03

TalentTuner