Home > Software engineering >  C# passing Func with parameters where 1 parameter is set while passing and the others are set inside
C# passing Func with parameters where 1 parameter is set while passing and the others are set inside

Time:10-28

Hi have created this method to read from excel:

        public static Dictionary<int, TreeItemModel> ExcelReader(FileUploadModel upload,
            Func<Dictionary<int, string>, Row, object, Action> func)
        {
            try
            {
                var dict = new Dictionary<int, TreeItemModel>();
                using (var doc = SpreadsheetDocument.Open(upload.Stream, false))
                {
                    var workbookPart = doc.WorkbookPart;

                    var worksheetPart = workbookPart.WorksheetParts.First();

                    var sheetData = worksheetPart.Worksheet.Elements<SheetData>().First();

                    var stringTable = LoadSharedStringDictionarySax(workbookPart.SharedStringTablePart);

                    foreach (var r in sheetData.Elements<Row>())
                    {
                        func(stringTable, r, dict);
                    }
                }

                upload.Stream.Close();

                upload.UploadCompletion = 100;

                return dict;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message);

                throw;
            }
        }        

I call this method in other class like this:

private async Task OnFilesDropped(FileUploadModel upload)
{
    var dict = new Dictionary<int, TreeItemModel>();

    OfficeHelper.ExcelExtension.ExcelReader(upload, ExcelToProjTree);
}

private static Action ExcelToProjTree(Dictionary<int, string> stringTable, Row r, Dictionary<int, TreeItemModel> dict)
{
  //Some stuff
}

The stringTable and r are set when the method is called but the dict I wanted to be set when I call ExcelReader

like this somehow:

private async Task OnFilesDropped(FileUploadModel upload)
{
    var dict = new Dictionary<int, TreeItemModel>();

    OfficeHelper.ExcelExtension.ExcelReader(upload, () => ExcelToProjTree(dict));
}

Is it possible? if yes, how?

CodePudding user response:

Since you'll be supplying a static object parameter argument (this is known as partial application btw), you'll want to remove that from the parameter list of the resulting Func type:

public static Dictionary<int, TreeItemModel> ExcelReader(FileUploadModel upload,
        Func<Dictionary<int, string>, Row, Action> func) { /* */ }

Then make sure the lambda you supply as an argument to ExcelReader has the correct signature as well (it should still accept Dictionary<int, string> and Row arguments):

OfficeHelper.ExcelExtension.ExcelReader(upload, (stringTable, row) => ExcelToProjTree(stringTable, row, dict));

And finally update the invocation of the function so that you only pass the first two parameter arguments:

func(stringTable, r); // `dict` will automatically be bound inside of `func`

Given that func still returns an Action, you might want to invoke that right away:

func(stringTable, r)();

CodePudding user response:

You can use Lazy<T>

private Lazy<Dictionary<int, TreeItemModel>> dict;

// Constructor
public YourClass()
{
    this.dict = Lazy<Dictionary<int, TreeItemModel>>(
        () => ExcelToProjTree(new Dictionary<int, TreeItemModel>()));
}

private async Task OnFilesDropped(FileUploadModel upload)
{
    var dict = new Dictionary<int, TreeItemModel>();

    // ExcelToProjTree Will be eveluated only now
    OfficeHelper.ExcelExtension.ExcelReader(upload, () => dict.Value);
}
  • Related