传递带有额外参数的委托函数

17

我有一个委托,它看起来像下面这样:

public delegate bool ApprovalPrompt(ApprovalType type, int receipt, params string[] info);

我希望调用的函数需要将这种类型的委托作为参数接受。然而,在一个特定的调用函数中,我想向与该委托匹配的函数传递一些额外的数据。

这是实现函数的签名:

private static bool LogApprovalNeeded(FraudFilterUtilities.ApprovalType type, int receipt, params string[] info)

现在它被称为以下内容:

PrepareReceipt(LogApprovalNeeded);

I'd like it to be:

private static bool LogApprovalNeeded(Customer cust, FraudFilterUtilities.ApprovalType type, int receipt, params string[] info)

理想情况下,应该按照以下方式使用:

PrepareReceipt(LogApprovalNeeded(myCustomer))

我该如何实现这个功能?我不想在类中声明一个字段来保存Customer参数,以便在一个函数和回调之间传递...

5个回答

30
您可以使用lambda函数来“柯里化”您的函数:
PrepareReceipt((type, receipt, info) => 
    LogApprovalNeeded(myCustomer, type, receipt, info))

柯里化是指将一个函数的引用存储起来,但将其中一个或多个参数“固定”,从而改变该函数的签名。

当您的函数签名不需要委托提供的所有参数时,您还可以使用lambda表达式;通过在lambda表达式中不转发所有参数,您可以有效地丢弃参数。


我知道它一定有可能。谢谢! - Bobson
PrepareReceipt的签名是什么样子的? - mcmillab
@mcmillab 参数是 ApprovalPrompt - Servy

7
您可以使用lambda来实现您所需的功能。
PrepareReceipt((type, receipt, info) =>
               LogApprovalNeeded(myCustomer, type, receipt, info));

或者,将你的LogApprovalNeeded签名更改为:

static bool LogApprovalNeeded(ApprovalType type, int receipt, 
                              Customer cust = null, params string[] info)
{
}

但是会有些混淆,因为在cust之后已经定义了一个变量数量的参数。

编辑:正如Servy所指出的那样,签名的更改不会让您按照您描述的方式调用该方法。如果您将与Customer相关的逻辑移动到PrepareReceipt中,则不需要使用上述方法(这基本上生成一个新的匿名方法并在闭包中包装myCustomer)。


@Servy 同意,不会按照作者描述的方式工作,我会指出这一点。但是,如果他可以将涉及“Customer”的逻辑封装在“PrepareReceipt”中,那么他就不需要对其进行柯里化调用。 - e_ne
+1 - 很好的回答,我很感激你提供了另一种选择(尽管我确实认为这会让人感到困惑)。不过,我将接受Servy的答案,因为他还包括了官方术语。 - Bobson
@Eve - 我真希望我能封装它,但由于我们拥有的旧代码和新代码的混合,PrepareReceipt 无法与 Customer 对象一起工作。或者至少,它不能很有用地这样做。 - Bobson

1
如果您需要委托部分应用(参数减少)的通用解决方案,请查看NReco Commons开源库,它包含PartialDelegateAdapter,可以为任何委托类型执行此操作:
var logApprovalForCustomer = (new PartialDelegateAdapter(LogApprovalNeeded,
    new[] {myCustomer})).GetDelegate<Func<FraudFilterUtilities.ApprovalType,int,string[],bool>>();

在这个例子中,第一个参数已固定为myCustomer值。此外,它还尝试在运行时协调参数类型。

-3

您可以更改PrepareReceipt函数以接受一个额外的参数。签名看起来应该像这样public void PrepareReceipt(Customer customer, ApprovalPrompt approvalPrompt)来实现这一点。


1
如果函数不需要这个参数,那么就不应该这样做。这只会在其他地方引起混乱。 - Servy

-5

你不能将它传递给那个委托,因为该委托没有声明一个类型为Customer的参数。"简单的答案"是改变委托的签名以接受新的参数。

话虽如此,这也需要修改所有使用该委托的消费者。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接