(如何)绑定/重新绑定方法以使用不同签名的委托?

Cat*_*kul 11 c# delegates callback currying signals-slots

我是一个c ++开发人员,在c ++中使用了信号和插槽,这对我来说似乎与c#中的委托类似.我发现自己在寻找"绑定"提供的功能时感到茫然,并且觉得我必须遗漏一些东西.

我觉得像C++这样的东西应该可以在带有委托的c#中实现.这里有一些psudo代码,用于我将在c ++中做什么:

Slot<void> someCallback;

int foo(int i)
{
    std::cout << "Value: " << i << "\n";
    return i;
}

int main()
{
    int i = 0;
    Slot<int> someCallback = bind( fun_ptr(foo), i );
    ++i; // added to show that late evaluation would be a non-trivial difference
    int result = someCallback();
    assert( result == 0 );
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,我无法找到任何关于c#delegates的绑定/重新绑定的引用.我错过了什么吗?在c#中有一些根本不同的方法吗?

jas*_*son 15

在C#中我们做这样的事情:

class Program {
    static Action Curry<T>(Action<T> action, T parameter) {
        return () => action(parameter);
    }

    static void Foo(int i) {
        Console.WriteLine("Value: {0}", i);
    }
    static void Main(string[] args) {
        Action curried = Curry(Foo, 5);
        curried();
    }
}
Run Code Online (Sandbox Code Playgroud)

显然,该方法Foo对应于您的方法Foo,只需使用适当的调用Console.WriteLine而不是std::cout.

接下来,我们声明一个Curry接受a Action<T>并返回一个的方法Action.通常,a Action<T>是一个委托,它接受一个类型的参数T并返回void.特别Foo是,Action<int>因为它接受一个类型的参数int并返回void.至于返回类型Curry,它被声明为Action.一个Action是没有参数和返回的委托void.

定义Curry很有趣.我们使用lambda表达式定义一个动作,这是一种非常特殊的匿名委托形式.有效

() => action(parameter)
Run Code Online (Sandbox Code Playgroud)

void参数映射到action评估时间parameter.

最后,在Main我们宣布的实例Action命名curried是应用的结果Curry,以Foo与参数5.这与bind(fun_ptr(foo), 5)C++示例中的角色相同.

最后,我们curried通过语法调用新形成的委托curried().这就像someCallback()你的例子.

对此的奇特用语是currying.

作为一个更有趣的例子,请考虑以下事项:

class Program {
    static Func<TArg, TResult> Curry<TArg, TResult>(
        Func<TArg, TArg, TResult> func,
        TArg arg1
    ) {
        return arg => func(arg1, arg);
    }

    static int Add(int x, int y) {
        return x + y;
    }

    static void Main(string[] args) {
        Func<int, int> addFive = Curry<int, int>(Add, 5);
        Console.WriteLine(addFive(7));
    }
}
Run Code Online (Sandbox Code Playgroud)

这里我们声明一个Curry接受委托的方法(Func<TArg, TArg, TResult>它接受两个相同类型的参数TArg并返回一些其他类型的值TResult和一个类型的参数,TArg并返回一个接受一个类型参数TArg并返回一个类型的值的委托TResult(Func<TArg, TResult>).

然后,作为测试,我们声明一个Add接受两个类型参数的方法,int并返回类型int(a Func<int, int, int>)的参数.然后在Main我们实例化一个名为的新委托addFive,它就像一个向其输入参数添加五个的方法.从而

Console.WriteLine(addFive(7));
Run Code Online (Sandbox Code Playgroud)

12在控制台上打印.