(如何)可以绑定/重新绑定一个方法来处理不同签名的代理? [英] (How) is it possible to bind/rebind a method to work with a delegate of a different signature?

查看:208
本文介绍了(如何)可以绑定/重新绑定一个方法来处理不同签名的代理?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是一个c ++开发人员使用的信号和c ++中的插槽似乎与c#中的代理类似。我发现自己在寻找绑定提供的功能方面感到失落,觉得我一定是缺少某些东西。



我觉得像以下这样的东西,这在c ++中是可能的,在c#中应该是可以的。以下是我在c ++中做的一些psudo代码:

  Slot< void>一些

int foo(int i)
{
std :: cout<<< 值:<< i< \\\
;
return i;
}

int main()
{
int i = 0;
Slot< int> someCallback = bind(fun_ptr(foo),i);
++ i; //添加显示后期评估将是一个非平凡的差异
int result = someCallback();
assert(result == 0);
return 0;
}

不幸的是,我没有找到任何参考绑定/重新绑定关于c#代表。我错过了什么吗?在c#中有一些截然不同的方法吗?

解决方案

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

  class Program {
static Action Curry< T>(Action< T> action,T参数){
return =>动作(参数);
}

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

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



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



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

 ()=> action(参数)

void 参数被映射到动作参数中进行评估。



最后,在 Main 中,我们正在声明一个 Action的实例命名为 curried 这是将 Curry 应用于 Foo 与参数 5 。这在C ++示例中起着 bind(fun_ptr(foo),5)的作用。



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



这个花哨的术语是 currying



作为一个更有趣的例子,考虑以下几点:

  class Program {
static Func< TArg,TResult>咖喱< 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));
}
}

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



然后,作为测试,我们声明一个方法添加接受两个类型为 int 的参数,并返回一个参数类型为 int (a Func< int,int,int> )然后在 Main 中,我们实例化一个名为 addFive 的行为就像一个添加五个输入参数的方法,因此

  Console.WriteLine(addFive(7) ); 

打印 12 在c鞋底。


I'm a c++ developer having used signals & slots in c++ which to me seems to be analogous to delegates in c#. I've found myself at a loss in searching for the functionality provided by "bind", and feel I must be missing something.

I feel like that something like the following, which is possible in c++ should be possible in c# with delegates. Here is some psudo-code for what I would do in 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;
}

Unfortunately, I've not been able to find any reference to binding/rebinding with regards to c# delegates. Am I missing something? Is there some radically different way to do this in c#?

解决方案

In C# we do something like this:

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

Clearly the method Foo corresponds to your method Foo, just with the appropriate calls to Console.WriteLine instead of std::cout.

Next, we declare a method Curry that accepts an Action<T> and returns an Action. In general, an Action<T> is a delegate that accepts a single parameter of type T and returns void. In particular, Foo is an Action<int> because it accepts one parameter of type int and returns void. As for the return type of Curry, it is declared as an Action. An Action is a delegate the has no parameters and returns void.

The definition of Curry is rather interesting. We are defining an action using a lambda expression which is a very special form of an anonymous delegate. Effectively

() => action(parameter)

says that the void parameter is mapped to action evaluated at parameter.

Finally, in Main we are declaring an instance of Action named curried that is the result of applying Curry to Foo with the parameter 5. This plays the same role as bind(fun_ptr(foo), 5) in your C++ example.

Lastly, we invoke the newly formed delegate curried via the syntax curried(). This is like someCallback() in your example.

The fancy term for this is currying.

As a more interesting example, consider the following:

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

Here we are declaring a method Curry that accepts a delegate (Func<TArg, TArg, TResult> that accepts two parameters of the same type TArg and returns a value of some other type TResult and a parameter of type TArg and returns a delegate that accepts a single parameter of type TArg and returns a value of type TResult (Func<TArg, TResult>).

Then, as a test we declare a method Add that accepts two parameters of type int and returns a parameter of type int (a Func<int, int, int>). Then in Main we instantiate a new delegate named addFive that acts like a method that adds five to its input parameter. Thus

Console.WriteLine(addFive(7));

prints 12 on the console.

这篇关于(如何)可以绑定/重新绑定一个方法来处理不同签名的代理?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆