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<Dictionary<int, string>, Row, Action>
,然后在调用处传递(stringTable, r) => 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<int, string>
和 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<Dictionary<int, string>, Row>
所以 Actions 是返回 void 的方法,而 fucn 是返回总是正确的方法?
正确。所以如果func
是一个“一劳永逸”的函数(例如,没有返回),那么Action
可能是更合适的类型【参考方案2】:
您可以使用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);
【讨论】:
以上是关于C#传递带有参数的Func,其中1个参数在传递时设置,其他参数在内部设置的主要内容,如果未能解决你的问题,请参考以下文章
在 C++ (Arduino) 中将带有参数的函数作为参数传递
将带有参数的 c# 回调方法传递给 c++ dll 会导致 System.ExecutionEngineException