在 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
Using Action<T> as an argument in C# (mimicking a function pointer)
提问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 Action
method 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.