C# 传递带有额外参数的委托函数
我有一个代表,看起来如下所示:C# 传递带有额外参数的委托函数,c#,delegates,C#,Delegates,我有一个代表,看起来如下所示: public delegate bool ApprovalPrompt(ApprovalType type, int receipt, params string[] info); 我接受这种类型的委托作为要调用的函数的参数。但是,在一个特定的调用函数中,我想向与此委托匹配的函数传递一些额外的数据 这是执行功能的签名: private static bool LogApprovalNeeded(FraudFilterUtilities.ApprovalType
public delegate bool ApprovalPrompt(ApprovalType type, int receipt, params string[] info);
我接受这种类型的委托作为要调用的函数的参数。但是,在一个特定的调用函数中,我想向与此委托匹配的函数传递一些额外的数据
这是执行功能的签名:
private static bool LogApprovalNeeded(FraudFilterUtilities.ApprovalType type, int receipt, params string[] info)
PrepareReceipt((type, receipt, info) =>
LogApprovalNeeded(myCustomer, type, receipt, info))
它的名称如下:
PrepareReceipt(LogApprovalNeeded);
PrepareReceipt(LogApprovalNeeded(myCustomer))
我希望它是:
private static bool LogApprovalNeeded(Customer cust, FraudFilterUtilities.ApprovalType type, int receipt, params string[] info)
理想情况下,可按如下方式使用:
PrepareReceipt(LogApprovalNeeded);
PrepareReceipt(LogApprovalNeeded(myCustomer))
我怎样才能完成这样一件事?我不希望仅仅为了在一个函数和回调函数之间保存
Customer
参数而在类中声明字段…您可以使用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
之后已经定义了数量可变的参数,这可能会有点混乱
EDIT:正如Servy正确指出的那样,签名的更改不允许您调用所描述的方法。但是,如果将与Customer
相关的逻辑移动到PrepareReceipt
,则不需要使用上述方法(这基本上会生成一个新的匿名方法,并将myCustomer
包装在一个闭包中)。您可以使用lambda来“curry”您的函数:
private static bool LogApprovalNeeded(FraudFilterUtilities.ApprovalType type, int receipt, params string[] info)
PrepareReceipt((type, receipt, info) =>
LogApprovalNeeded(myCustomer, type, receipt, info))
curry函数是一个正式术语,用于存储对函数的引用,但其中一个或多个参数是“固定”的,从而改变方法的签名
当函数的签名不需要委托提供的所有参数时,您也可以使用lambda;您可以通过不转发lambda中的所有参数来有效地丢弃参数。您可以更改
PrepareReceipt
函数以获取附加参数。签名看起来类似于public void PrepareReceipt(Customer-Customer,ApprovalPrompt ApprovalPrompt)
的方法来完成此操作。您不能将其传递给该委托,因为该委托未声明Customer类型的参数。“简单答案”是更改委托的签名以接受新参数
也就是说,这还需要修改委托的所有使用者。如果您需要委托部分应用程序的通用解决方案(参数缩减),请查看开放源代码库,它包含可以对任何委托类型执行此操作的PartialDelegateAdapter:
var logApprovalForCustomer = (new PartialDelegateAdapter(LogApprovalNeeded,
new[] {myCustomer})).GetDelegate<Func<FraudFilterUtilities.ApprovalType,int,string[],bool>>();
var logApprovalForCustomer=(需要新的PartialDelegateAdapter(logApprovalForCustomer),
新[]{myCustomer})).GetDelegate();
在本例中,第一个参数是用myCustomer值固定的。此外,它还尝试在运行时协调参数类型。Lamba方法并不完美:它们没有属性,导致代码混乱。
如果您想避免这种方法,可以使用另一种方法,就像JavaScript的
.bind()
函数一样。该函数可以在C#中进行如下调整,使用带有一些扩展方法的静态类:
//This code requires the Nu-get plugin ValueTuple
using System.Diagnostics;
public static class Extensions
{
[DebuggerHidden, DebuggerStepperBoundary]
public static WaitCallback Bind(this Delegate @delegate, params object[] arguments)
{
return (@delegate, arguments).BoundVoid;
}
[DebuggerHidden, DebuggerStepperBoundary]
public static Func<object, object> BindWithResult(this Delegate @delegate, params object[] arguments)
{
return (@delegate, arguments).BoundFunc;
}
[DebuggerHidden, DebuggerStepperBoundary]
private static void BoundVoid(this object tuple, object argument)
{
tuple.BoundFunc(argument);
}
[DebuggerHidden, DebuggerStepperBoundary]
private static object BoundFunc(this object tuple, object argument)
{
(Delegate @delegate, object[] arguments) = ((Delegate @delegate, object[] arguments))tuple;
if (argument != null)
if (!argument.GetType().IsArray)
argument = new object[] { argument };
object[] extraArguments = argument as object[];
object[] newArgs = extraArguments == null ? arguments : new object[arguments.Length + extraArguments.Length];
if (extraArguments != null)
{
extraArguments.CopyTo(newArgs, 0);
arguments.CopyTo(newArgs, extraArguments.Length);
}
if (extraArguments == null)
return @delegate.DynamicInvoke(newArgs);
object result = null;
Exception e = null;
int argCount = newArgs.Length;
do
{
try
{
if (argCount < newArgs.Length)
{
object[] args = newArgs;
newArgs = new object[argCount];
Array.Copy(args, newArgs, argCount);
}
result = @delegate.DynamicInvoke(newArgs);
e = null;
} catch (TargetParameterCountException e2)
{
e = e2;
argCount--;
}
} while (e != null);
return result;
}
}
鉴于以下代码将生成一个Func
委托:
new Func<double, double, double>(Math.Pow).Bind(3, 2)
new Func<double, double, double>(Math.Pow).BindWithResult(3, 2)
newfunc(Math.Pow).BindWithResult(3,2)
我知道这必须是有可能的。谢谢!PrepareReceipt的签名是什么样子的?@mcmillab参数是ApprovalPrompt
。如果函数不需要这个参数,那就不适合这样做。它最多只会在使用它的其他地方造成混乱。@Servy同意,在中不起作用按照作者描述的方式,我要指出。如果他能将涉及Customer
的逻辑封装在PrepareReceipt
中,那么他就不需要去讨好自己的电话了。+1-回答得好,我也很欣赏这个替代方案(尽管我绝对同意这会让人困惑),但我将接受Servy的,因为他也包含了这方面的官方术语。@Eve-我真的希望我能封装它,但由于我们有新旧代码的混合,PrepareReceipt
不能与客户
对象一起工作。或者至少,它不能有效地这样做。