【问题标题】:C# passing Func with parameters where 1 parameter is set while passing and the others are set insideC#传递带有参数的Func,其中1个参数在传递时设置,其他参数在内部设置
【发布时间】:2021-12-12 00:52:33
【问题描述】:

您已经创建了这个从 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;
            }
        }        

我在其他类中这样调用这个方法:

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
}

stringTable 和 r 是在调用方法时设置的,但是我想在调用 ExcelReader 时设置 dict

像这样:

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

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

有可能吗?如果是,怎么做?

【问题讨论】:

  • func的参数类型改为Func&lt;Dictionary&lt;int, string&gt;, Row, Action&gt;,然后在调用处传递(stringTable, r) =&gt; ExcelToProjTree(stringTable, r, dict)
  • @MathiasR.Jessen 在我称之为 foreach 的地方我应该放什么?
  • func(stringTable, r);(因为您已经在 lambda 中提供了 dict 参数)
  • @MathiasR.Jessen 我会试试的 ;)

标签: c# function parameters func


【解决方案1】:

由于您将提供静态object 参数参数(这称为partial application btw),因此您需要将其从生成的Func 类型的参数列表中删除:

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

然后确保您作为参数提供给 ExcelReader 的 lambda 也具有正确的签名(它仍应接受 Dictionary&lt;int, string&gt;Row 参数):

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

最后更新函数的调用,让你只传递前两个参数参数:

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

鉴于func 仍返回Action,您可能希望立即调用它:

func(stringTable, r)();

【讨论】:

  • 通过调用 func(stringTable, r)();我得到以下异常“对象引用未设置为对象的实例”。动作返回 null,所以我应该不带 () 对吗?
  • 效果非常好!谢谢你的帮助我以前从未做过函数式编程;)
  • @MarchalPT 不客气!如果您实际上并不打算返回 Action,则可能需要将 func 的签名更改为 Action&lt;Dictionary&lt;int, string&gt;, Row&gt;
  • 所以 Actions 是返回 void 的方法,而 fucn 是返回总是正确的方法?
  • 正确。所以如果func 是一个“一劳永逸”的函数(例如,没有返回),那么Action 可能是更合适的类型
【解决方案2】:

您可以使用Lazy&lt;T&gt;

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

【讨论】:

    猜你喜欢
    • 2017-04-06
    • 2014-02-15
    • 1970-01-01
    • 2011-08-31
    • 1970-01-01
    • 2012-05-02
    • 1970-01-01
    • 1970-01-01
    • 2014-07-03
    相关资源
    最近更新 更多