在 C# 中使用 Action<T> 作为参数(模仿函数指针)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1065950/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 07:23:23  来源:igfitidea点击:

Using Action<T> as an argument in C# (mimicking a function pointer)

c#delegates

提问by cgyDeveloper

I need to write a delegate function that can 'wrap' some while/try/catch code around a basic UDP call to verify the link. I made it work for Func for a function that has no arguments, but I can't make it work for Action, which has an argument (but no return). I can't seem to pass in the argument in a logical way without the compiler complaining.

我需要编写一个委托函数,该函数可以围绕基本 UDP 调用“包装”一些 while/try/catch 代码以验证链接。我使它适用于没有参数的函数的 Func,但我不能使它适用于 Action,它有一个参数(但没有返回)。我似乎无法在没有编译器抱怨的情况下以合乎逻辑的方式传递参数。

Am I going about this all wrong? I'm new to C# and I'm essentially trying to mimick the idea of a function pointer. Should I not be overloading this function? I know you can't overload delegates (I assume that's why Func and Action exist).

我在这一切都错了吗?我是 C# 的新手,我基本上是在尝试模仿函数指针的想法。我不应该重载这个函数吗?我知道你不能重载委托(我认为这就是 Func 和 Action 存在的原因)。

This works:

这有效:

protected TResult udpCommand<TResult>(Func<TResult> command)
        {
            TResult retValue = default(TResult);
            while (!linkDownFail)
            {
                try
                {
                    retValue = command();
                    break;
                }
                catch
                {
                    LinkStateCallBack(ip, getLinkStatus());
                    if (linkDownFail) throw new LinkDownException();
                    Thread.Sleep(100);
                }
            }
            return retValue;
        }

But this does not:

但这不会:

protected void udpCommand<T>(Action<T> command(T value))
        {
            while(!linkDownFail)
            {
                try
                {
                    command(value);
                    break;
                }
                catch
                {
                    LinkStateCallBack(ip, getLinkStatus());
                    if (linkDownFail) throw new LinkDownException();
                    Thread.Sleep(100);
                }
            }
            return;
        }

Calling convention (for one that works):

调用约定(适用于一个有效的约定):

udpCommand<uint>(someUdpCommand);

采纳答案by Michael Meadows

If you want this to be generic enough to handle any number of arguments, try using the non-genernic Action delegate:

如果您希望它足够通用以处理任意数量的参数,请尝试使用非通用 Action 委托:

protected void udpCommand(Action command)
{
    while(!linkDownFail)
    {
        try
        {
            command();
            break;
        }
        catch
        {
            LinkStateCallBack(ip, getLinkStatus());
            if (linkDownFail) throw new LinkDownException();
            Thread.Sleep(100);
        }
    }
    return;
}

In C# 3.0, you can call it like this:

在 C# 3.0 中,您可以这样调用它:

udpCommand(() => noParameterMethod());
udpCommand(() => singleParameterMethod(value));
udpCommand(() => manyParameterMethod(value, value2, value3, value4));

In C# 2.0 it's a little uglier:

在 C# 2.0 中,它有点丑陋:

udpCommand(delegate { noParameterMethod(); });
udpCommand(delegate { singleParameterMethod(value); });
udpCommand(delegate { manyParameterMethod(value, value2, value3, value4); });

This gives you deferred execution without locking you into a particular method signature.

这使您可以延迟执行,而不会将您锁定在特定的方法签名中。

EDIT

编辑

I just notice I kinda stole Marc Gravell's comment... apologies Marc. To answer how you might reduce your duplication, you can have the Actionmethod call the Func<T>method, like this:

我只是注意到我有点偷了 Marc Gravell 的评论……向 Marc 道歉。要回答如何减少重复,您可以让该Action方法调用该Func<T>方法,如下所示:

protected void udpCommand(Action command)
{
    udpCommand(() => { command(); return 0; });
}

I believe (and I may be wrong) that returning 0 is no more costly than (implicitly) returning void, but I may be way off here. Even it it does have a cost, it would only put a tiny itty bitty snoodge extra on the stack. In most cases, the additional cost won't ever cause you any grief.

我相信(我可能是错的)返回 0 并不比(隐式)返回 void 成本更高,但我可能离这里很远。即使它确实有成本,它也只会在堆栈中多放一点点小东西。在大多数情况下,额外的费用永远不会让您感到悲伤。

回答by Michael Bray

I think you just need to take out the (T value) after 'command'.

我认为您只需要在“命令”之后取出(T 值)即可。

回答by Marc Gravell

Do you mean:

你的意思是:

    protected void udpCommand<T>(Action<T> command, T value) {...}

With calling:

通过调用:

udpCommand(someUdpCommand, arg);

Note that this may work better on C# 3.0, which has stronger generic type inference than C# 2.0.

请注意,这可能在 C# 3.0 上效果更好,它比 C# 2.0 具有更强的泛型类型推断。

回答by JP Alioto

Are you trying to do this ...

你想这样做吗...

protected void udpCommand<T>(Action<T> command, T value)
{
   while(!linkDownFail)
   {
    try                
    {
      command(value);
      // etc.
    }
  }
}

Then it would work like this ...

然后它会像这样工作......

public void ActionWithInt( int param )
{
   // some command
}

Action<int> fp = ActionWithInt;

udpCommand<int>( fp, 10 );  // or whatever.