【问题标题】:Using Action<T> as an argument in C# (mimicking a function pointer)在 C# 中使用 Action<T> 作为参数(模仿函数指针)
【发布时间】:2009-07-01 05:18:48
【问题描述】:

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

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

这行得通:

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

但这不是:

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

调用约定(适用的):

udpCommand<uint>(someUdpCommand);

【问题讨论】:

  • 附加 - 你实际上并不需要 T;你可以只取Action(无参数),然后调用:udpCommand(() => SomeMethod(123));
  • 这是否允许我为 udpCommand 提供不同数量的输入参数,而不会使它重载,例如最多 4 个参数?这就是我需要做的。我还需要一个 Func 和一个 Action 吗?

标签: c# delegates


【解决方案1】:

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

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

在 C# 3.0 中,您可以这样称呼它:

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

在 C# 2.0 中它有点丑:

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

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

编辑

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

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

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

【讨论】:

  • 我喜欢这个地方。正是我作为 C#/VS.NET 菜鸟所需要的。谢谢。
【解决方案2】:

你的意思是:

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

有调用:

udpCommand(someUdpCommand, arg);

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

【讨论】:

  • 啊哈!这似乎工作......至少编译器不再抱怨了。 Microsoft 的示例并没有真正涵盖我的用例。谢天谢地,我使用的是 C# 3.0。里程在 C# 2.0 上可能有所不同。
【解决方案3】:

我认为你只需要在'命令'之后取出(T值)。

【讨论】:

  • 编译器抱怨有或没有 T。
  • 嗯,我认为是因为问题有点模棱两可,但我应该意识到您也试图将参数传递给 Action in。我同意您接受的答案中提供的解决方案,它也简单地传递了一个 T 值(尽管不在括号中)。如果您在代码块中有可用的“价值”,那么我认为它可以正常工作。
  • 啊,是的,我相信这也可以。感谢您的反馈。
【解决方案4】:

你是不是要这么做……

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

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

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

Action<int> fp = ActionWithInt;

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-11-28
    • 1970-01-01
    • 2011-05-25
    • 2010-12-22
    • 2013-09-12
    • 1970-01-01
    相关资源
    最近更新 更多