Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/299.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ssh/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 传递带有额外参数的委托函数_C#_Delegates - Fatal编程技术网

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
不能与
客户
对象一起工作。或者至少,它不能有效地这样做。