有额外的参数传递委托功能(Passing delegate function with extra

2019-07-18 04:58发布

我有一个代表,它看起来像下面:

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);

我想它是:

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

在理想情况下将被使用如下:

PrepareReceipt(LogApprovalNeeded(myCustomer))

我怎样才能做到这样的事情? 我宁愿不需要在类中声明的字段仅仅是保持Customer一个函数和回调之间的参数...

Answer 1:

您可以使用lambda来“讨好”你的函数:

PrepareReceipt((type, receipt, info) => 
    LogApprovalNeeded(myCustomer, type, receipt, info))

讨好一个功能是用于存储参照功能,但有一个或多个“固定”的参数,从而改变了该方法的签名的正式术语。

您还可以使用lambda当你的函数的签名并不需要所有的委托提供的参数; 可以有效地在lambda不向前传递的所有参数丢弃参数。



Answer 2:

您可以使用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理所当然指出,签名的变化不会让你调用这个方法像你描述。 如果移动相关逻辑CustomerPrepareReceipt ,不过,你不需要使用上面的方法(这基本上生成一个新的匿名方法和包装myCustomer在一个封闭。



Answer 3:

如果您需要代表通用的解决方案部分应用程序(参数减少)看看到NReco共享开源库,它包含PartialDelegateAdapter能够这样做的任何委托类型:

var logApprovalForCustomer = (new PartialDelegateAdapter(LogApprovalNeeded,
    new[] {myCustomer})).GetDelegate<Func<FraudFilterUtilities.ApprovalType,int,string[],bool>>();

在这个例子中第一参数是固定的myCustomer值。 另外它还试图在运行时协调的参数类型。



Answer 4:

兰巴方法并不完美:他们没有属性和他们为乱码贡献。
如果你想避免那种方法,你可以用另一种方式,它就像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;
    }
}

现在,您可以为您的方法(不是拉姆达)的委托,并分配给它的一些固定的参数:

MessageBox.Show(new Func<double, double, double>(Math.Pow).BindWithResult(3, 2)(null).ToString()); //This shows you a message box with the operation 3 pow 2

所以,下面的代码会产生WaitCallback代表:

new Func<double, double, double>(Math.Pow).Bind(3, 2)

而下面的代码将产生一个Func<object, object>委托:

new Func<double, double, double>(Math.Pow).BindWithResult(3, 2)


Answer 5:

您可以更改PrepareReceipt功能采取额外的参数。 签名会看起来像public void PrepareReceipt(Customer customer, ApprovalPrompt approvalPrompt)做到这一点。



Answer 6:

你不能把它传递给该委托的委托不声明类型客户的参数。 “简单的回答”是改变了代表的签名采取新的参数。

尽管如此,这也将要求所有消费者的委托的修改。



文章来源: Passing delegate function with extra parameters
标签: c# delegates