C#传递带有参数的Func,其中1个参数在传递时设置,其他参数在内部设置

Posted

技术标签:

【中文标题】C#传递带有参数的Func,其中1个参数在传递时设置,其他参数在内部设置【英文标题】:C# passing Func with parameters where 1 parameter is set while passing and the others are set inside 【发布时间】: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 我会试试的 ;) 【参考方案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);

【讨论】:

以上是关于C#传递带有参数的Func,其中1个参数在传递时设置,其他参数在内部设置的主要内容,如果未能解决你的问题,请参考以下文章

将多个参数从 c# 传递给 python

在 C++ (Arduino) 中将带有参数的函数作为参数传递

PHP函数-不定参数的传递

将带有参数的 c# 回调方法传递给 c++ dll 会导致 System.ExecutionEngineException

Unity基础(26)-委托使用

c语言向函数传递函数作为参数